如何使用DI容器(Autofac)来注册带参数的服务

问题描述 投票:0回答:3

我在ViewModel上有以下代码片段,我想摆脱new关键字,并将创建的责任交给DI容器。但是,我有一些困难能够将IDataFileReader注入我的ViewModel,因为给定的参数progressViewModel ProgressBarValue属性相关联。

基本上,我的文件阅读器需要将进度作为参数,因此我可以在我的UI上显示进度。

所以问题是,如何在IDataFileReader上使用AutoFac模块注册ViewModelLocator

ViewModel.cs

  ProgressBarIsIndetermined = true;
  var progress = new Progress<int>(status => { ProgressBarValue = status; });

  await Task.Run(() =>
  {
    IDataFileReader fileImporter = new DataFileReader(progress);
    DataSet = new ObservableCollection<MeasurementPoint>(fileImporter.DataSet);
  });

我正在使用Mvvm Light viewmodelLocator和MVVM与WPF。对于不需要任何参数的简单服务,我可以通过构造函数注入轻松实现。

ViewModelLocator.cs

static ViewModelLocator()
{
  var builder = new ContainerBuilder();
  builder.RegisterModule<AutofacModule>();
  var container = builder.Build();
  ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
}

public SettingsViewModel SettingsViewModel => ServiceLocator.Current.GetInstance<SettingsViewModel>();

AutoFacModule.cs

以下模块只是一个草案,可用于没有参数的简单构造函数注入。

  public class AutofacModule : Module
  {
    protected override void Load(ContainerBuilder builder)
    {
      builder.RegisterType<DataFileReader>().As<IDataFileReader>();   
      builder.RegisterType<SettingsViewModel>().AsSelf().SingleInstance();

    }
  }
c# wpf autofac mvvm-light
3个回答
1
投票

另一种选择是注入一个可以创建IDataFileReader的委托,而不是已经实例化的委托。这将允许您将Progress对象传递给它。

Autofac支持delegate factories。这可能会导致类似以下内容(未经测试):

public class DataFileReader : IDataFileReader
{
  public delegate DataFileReader Factory(Progress progress);

  public Shareholding(Progress progress)
  {
    Progress = progress;
  }
}

public class ViewModel
{
  private readonly DataFileReader.Factory factory;
  public ViewModel(DataFileReader.Factory dataFileReaderFactory)
  {
    factory = dataFileReaderFactory;
  }

  ...
  IDataFileReader fileImporter = factory(progress);
}

1
投票

基本上,你不能以很好的方式做到这一点:)你应该首先问自己,为什么DataFileReader关心进步。也许,其他事情应该观察进展并向全世界报告?

我还建议避免使用ServiceLocator模式。类应该只包含通过构造函数显式注入的明确定义的依赖项。在我看来,属性注入也应该被视为反模式。


1
投票

你想要的是DataFileReader更新你的ViewModel的ProgressBarValue属性。最简单的方法是在OnUpdate上添加DataFileReader方法

reader.OnUpdate(status => this.ProgressBarValue = status.PercentProgress); 

通过这样做,你将为你的IDataFileReader界面添加一个新的责任,这可能不合适并打破Single Responsibility Principle

在这种情况下,通常会引入一个仅关注一件事的新组件。

public interface IProgressObserver
{
    void OnUpdate(Action<Int32> updater);
    void Update(Int32 percent);
}

你的DataFileReader可以依赖这个组件,并在需要时调用Update方法。您的ViewModel将具有IProgressObserver依赖项和IDataFileReader

IProgressObserver的一个可能的实现可以很简单

public class ProgressObserver : IProgressObserver
{
    private Action<Int32> _updater = _ => { };

    public void Update(Int32 percent)
    {
        this._updater(percent);
    }
    public void Register(Action<Int32> updater)
    {
        this._updater = updater;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.