如何使用 DI 容器(Autofac)注册带参数的服务
How to use DI-container (Autofac) to register service with parameters
我的 ViewModel
上有以下代码片段,我想去掉 new
关键字并将创建的责任交给 DI 容器。但是,我在将 IDataFileReader
注入我的 ViewModel
时遇到了一些困难,因为给定的参数 progress
绑定到 ViewModel
ProgressBarValue
属性.
基本上,我的文件 reader 需要进度作为参数,因此我可以在我的 UI 上显示进度。
So the question is, how to register IDataFileReader
with AutoFac modules on
ViewModelLocator
?
VieModel.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);
});
我在 WPF 中使用 Mvvm Light viewmodelLocator
和 MVVM。对于不需要任何参数的简单服务,我可以通过构造函数注入轻松实现。
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();
}
}
基本上,您不能很好地做到这一点 :) 您应该首先问问自己,为什么 DataFileReader
关心进度。也许,应该有其他东西来观察进展并将其报告给世界?
我还建议避免使用 ServiceLocator 模式。 类 应该只包含通过构造函数显式注入的明确定义的依赖项。在我看来,属性注入也应该被视为反模式。
您想要的是 DataFileReader
更新 ViewModel 的 ProgressBarValue
属性。最简单的方法是在 DataFileReader
上添加 OnUpdate
方法
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;
}
}
另一种选择是注入一个可以创建 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);
}
我的 ViewModel
上有以下代码片段,我想去掉 new
关键字并将创建的责任交给 DI 容器。但是,我在将 IDataFileReader
注入我的 ViewModel
时遇到了一些困难,因为给定的参数 progress
绑定到 ViewModel
ProgressBarValue
属性.
基本上,我的文件 reader 需要进度作为参数,因此我可以在我的 UI 上显示进度。
So the question is, how to register
IDataFileReader
with AutoFac modules onViewModelLocator
?
VieModel.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);
});
我在 WPF 中使用 Mvvm Light viewmodelLocator
和 MVVM。对于不需要任何参数的简单服务,我可以通过构造函数注入轻松实现。
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();
}
}
基本上,您不能很好地做到这一点 :) 您应该首先问问自己,为什么 DataFileReader
关心进度。也许,应该有其他东西来观察进展并将其报告给世界?
我还建议避免使用 ServiceLocator 模式。 类 应该只包含通过构造函数显式注入的明确定义的依赖项。在我看来,属性注入也应该被视为反模式。
您想要的是 DataFileReader
更新 ViewModel 的 ProgressBarValue
属性。最简单的方法是在 DataFileReader
OnUpdate
方法
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;
}
}
另一种选择是注入一个可以创建 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);
}