我最近开始了一个WPF项目,该项目当然遵循MVVM模式。我试图一次(仅在组合根中,即在应用程序的Startup事件处理程序中)解析 View 模型的对象图,以便不依赖于我的IoC容器:

public partial class App : Application
{
    private void OnStartup(object sender, StartupEventArgs e)
    {
       // Composition Root

       var container = new UnityContainer();

       container.RegisterType<IResidentListViewModel, ResidentListViewModel>();
       container.RegisterType<IMainViewModel, MainViewModel>();

       container.RegisterType<IDataService, DataService>();

       var mainWindow = new MainWindow(container.Resolve<IMainViewModel>());

       Current.MainWindow = mainWindow;
       mainWindow.Show();
    }
}

ResidentListViewModel依次取决于IDataService:
private readonly IDataService dataService;

public ResidentListViewModel(IDataService dataService)
{
   if (dataService == null)
      throw new ArgumentNullException("dataService");

   this.dataService = dataService;
}

这不是问题,因为容器可以解决该依赖性。

但是,ResidentListviewModel具有一个可以击中IDataService的Residents属性:
private readonly ObservableCollection<IResidentViewModel> residents = new ObservableCollection<IResidentViewModel>();

public ObservableCollection<IResidentViewModel> Residents
{
   get
   {
      if (this.residents == null)
         LoadResidents();

      return this.residents;
   }
}

当加载数据时,问题开始了:
private async Task LoadResidents()
{
   if (!IsLoading)
   {
      IsLoading = true;

      var models = await this.dataService
         .ListResidents();

      var viewModels = models
         .OrderBy(m => m.Name)
         .ThenBy(m => m.Vorname)
         .Select(m => new ResidentViewModel(m.Z_PF, string.Format("{0}, {1}", m.Name, m.Vorname)));

      residents.Clear();

      foreach (var viewModel in viewModels)
         residents.Add(viewModel);

      IsLoading = false;
   }
}

我知道,我知道反复添加到ObservableCollection是不行的,但是请在这里接受。在那里看到那个 Shiny 的"new"关键字吗?那才是真正的罪魁祸首。我不知道如何在不辞职到服务定位器(“实例工厂”)的情况下摆脱它,根据我最喜欢的DI书籍作者Mark Seemann的说法,这反过来又是一种反模式。会推荐给任何C#开发人员)。

当然,我可以注入(inject)VM本身的列表,但是这样会将数据检索移到合成的根目录(听起来像个坏主意),我可以很容易地想到一个场景,用户选择一个条目,然后选择代码必须根据该选择来检索数据,这使我回到了第一位。

所以问题是:是否有一种方法可以通过组合根目录进行相同的单个调用来处理此问题?

最佳答案

你近了不是实例工厂反模式,而是abstract factory模式:

var viewModels = models
    .OrderBy(m => m.Name)
    .ThenBy(m => m.Vorname)
    .Select(m => residentViewModelFactory.CreateInstance(m));
residentViewModelFactory当然是通过构造函数注入(inject)作为接口(interface)提供的依赖项,它使一切都很好且可测试,并且当然可以从组合根目录设置(您将工厂注册为组件之一)。

09-17 01:53