我有通用工厂
public interface IViewModelFactory<T> where T : IViewModel
{
T Create<TU>(TU par);
}
public class ViewModelFactory<T> : IViewModelFactory<T> where T : IViewModel
{
private readonly ILifetimeScope _scope;
public ViewModelFactory(ILifetimeScope scope)
{
_scope = scope;
}
public T Create<TU>(TU par)
{
return _scope.Resolve<T>(new TypedParameter(typeof(TU), par));
}
}
我可以用来解析我的窗口类中的viewmodel工厂:
public WRPersons(IViewModelFactory<MRPersons> viewModelFactory)
{
var viewModel = viewModelFactory.Create(new MRPersonsUseCaseParams { Filter = 2 });
...
}
ViewModel通过以下代码实现
public class MRPersons : IViewModel
{
public MRPersons(MRPersonsUseCaseParams par)
{
_filter = par.Filter;
}
}
public class MRPersonsUseCaseParams
{
public int Filter { get; set; }
}
在我的作文根中注册如下:
var builder = new ContainerBuilder();
builder.RegisterType<ViewModelFactory<MRPersons>>().As<IViewModelFactory<MRPersons>>();
builder.RegisterType<MRPersons>();
正如您可以看到的每个新的ViewModel(现在只有它的MRPerson),我需要在我的组合根中创建两个条目。因此,对于MRCar,它将是:
builder.RegisterType<ViewModelFactory<MRCar>>().As<IViewModelFactory<MRCar>>();
builder.RegisterType<MRCar>();
我想以某种方式自动化这些注册。我尝试了RegisterAssemblyTypes / AsClosedTypesOf但没有成功。有人可以帮帮我吗?
修改
基于答案代码行
builder.RegisterType<ViewModelFactory<MRPersons>>().As<IViewModelFactory<MRPersons>>();
替换为
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
全自动注册如下:
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass).AsSelf();
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
对于更好的可测试解决方案,甚至可以通过IMRPersons替换MRPersons:
public class MRPersons : IViewModel, IMRPersons
{
public MRPersons(MRPersonsUseCaseParams par)
{
_filter = par.Filter;
}
}
public class MRPersonsUseCaseParams
{
public int Filter { get; set; }
}
public interface IMRPersons
{
}
因此,组合根中的注册看起来像(需要被纠正)
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass).As<??????>.AsSelf();
这将允许我以下列方式将工厂传递给构造函数:
public WRPersons(IViewModelFactory<IMRPersons> viewModelFactory)
{
var viewModel = viewModelFactory.Create(new MRPersonsUseCaseParams { Filter = 2 });
...
}
EDIT2: 在与Cyril Durand聊天期间,他为ViewModelFactory提供了解决方案,而没有参考ILifetimeScope。这是一个代码:
public interface IViewModelFactory2<T, TU> where T : IViewModel
{
T Create(TU par);
}
public class ViewModelFactory2<T, TU> : IViewModelFactory2<T, TU> where T : IViewModel
{
private readonly Func<TU, T> _factory;
public ViewModelFactory2(Func<TU, T> factory)
{
_factory = factory;
}
public T Create(TU par)
{
return _factory(par);
}
}
我的原始工厂也很好,因为它在组合根中呈现,可以使用对DI容器的强引用。
答案 0 :(得分:1)
您希望将ViewModelFactory<>
注册为IViewModelFactory<>
,您可以使用RegisterGeneric
方法进行注册。
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
然后,您无需任何其他注册即可解决IViewModelFactory<MRCar>
。
有关详细信息,请参阅Registration Concepts - Open Generic Components
问题的第二部分:
为了获得更好的可测试解决方案,甚至可以
MRPersons
替换IMRPersons
这并不容易,因为无法知道使用哪个界面。您可以使用等同于AsImplementedInterfaces
的{{1}},但如果您有大量已实现的界面,则可能会出现问题。
As<IMRPersons>().As<IViewModel>()
或者您可以使用将所有builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly())
.Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass)
.AsImplementedInterfaces();
注册为X
的约定,但我并不是此类注册的忠实粉丝。
IX
顺便说一句,在聊天之后,我们发现你根本不需要builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass)
.As(t => t.GetInterfaces().Where(i => i.Name.EndsWith(t.Name)));
,但你只需依赖IViewModelFactory<>