gpt4 book ai didi

c# - 为实现接口(interface)的所有类型注册通用工厂

转载 作者:行者123 更新时间:2023-11-30 17:42:45 32 4
gpt4 key购买 nike

我有通用工厂

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));
}
}

我可以用它来解析我的窗口类中的 View 模型工厂:

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 });
...
}

编辑 2:在与 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 容器的强引用。

最佳答案

您想注册ViewModelFactory<>作为IViewModelFactory<> , 你可以使用 RegisterGeneric 来做到这一点方法。

builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>)); 

然后你就可以解析IViewModelFactory<MRCar>没有任何其他注册。

参见 Registration Concepts - Open Generic Components了解更多信息


对于问题的第二部分:

For better testable solution it would be fine to even replace MRPersons by IMRPersons

这不是那么容易,因为无法知道使用哪个接口(interface)。您可以使用 AsImplementedInterfaces这相当于 As<IMRPersons>().As<IViewModel>()但如果你有很多已实现的接口(interface),这可能是个问题。

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<>完全没有,但你只需要依赖 Func<TParam, T>

关于c# - 为实现接口(interface)的所有类型注册通用工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31675233/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com