我如何动态地注册具有Unity名称的泛型类? [英] How can I dynamically register generic classes with a name with Unity?
问题描述
我有一个带有一个BaseClass的很多类(300+)的程序集,我想用一个接口注册一个泛型类。
I have an assembly with a lot of classes (300+) with a BaseClass and I want register a generic class with a interface.
如果要解析接口的一组对象,请按{名称}进行注册。
我想在 MainViewModel 中自动创建一个对象数组。
With unity you have to register by {Name} if you want to resolve an array of objects of the interface. I want an array of objects in the MainViewModel automatically.
有没有一种方法可以通过反射自动执行此操作?
有何建议?
Is there a way to automate this with reflection? Any suggestions?
示例(伪):
Example (pseudo):
public class BaseClass
{
public void doFoo();
}
public ClassNumber001 : BaseClass
{
}
public ClassNumber002 : BaseClass
{
}
public interface ISuperman
{
}
public class Superman : ISuperman where T : BaseClass
{
}
public MainViewModel(IEnumerable<ISuperman> lotsofSuperman)
{
}
举例来说:
Working example by hand:
container.RegisterType<ISuperman, Superman <ClassNumber001>>("ClassNumber001");
container.RegisterType<ISuperman, Superman <ClassNumber002>>("ClassNumber002");
container.RegisterType<IEnumerable<ISuperman>, ISuperman[]>();
推荐答案
是的,您需要使用反射轻松创建所有你想要的映射。由于您使用的是Unity 3,因此您可以利用按公约注册,以便在注册课程时提供帮助(更重的提升)。
Yes, you'll need to use reflection to easily create all of the mappings that you want. Since you are using Unity 3 you can take advantage of Registration by Convention to provide help (with the heavier lifting) in registering the classes.
我已将您的伪代码编译成实际的代码:
I've taken your pseudo code and translated it into real code:
public abstract class BaseClass
{
public abstract void DoFoo();
}
public class ClassNumber001 : BaseClass
{
public override void DoFoo()
{
Console.WriteLine("001 Foo");
}
}
public class ClassNumber002 : BaseClass
{
public override void DoFoo()
{
Console.WriteLine("002 Foo");
}
}
public interface ISuperman
{
void Do();
}
public class Superman<T> : ISuperman where T : BaseClass
{
private T baseClass;
public Superman(T baseClass)
{
this.baseClass = baseClass;
}
public void Do()
{
this.baseClass.DoFoo();
}
}
public class MainViewModel
{
public MainViewModel(IEnumerable<ISuperman> lotsofSuperman)
{
foreach(ISuperman superman in lotsofSuperman)
{
superman.Do();
}
}
}
然后按惯例注册注册所有泛型:
Then use registration by convention to register all the generics:
IUnityContainer container = new UnityContainer();
container.RegisterTypes(
AllClasses.FromAssembliesInBasePath().Where(t => typeof(BaseClass).IsAssignableFrom(t))
.Select(t => typeof(Superman<>).MakeGenericType(t)),
t => new Type[] { typeof(ISuperman) },
t => t.GetGenericArguments().First().Name,
WithLifetime.Transient);
container.RegisterType<IEnumerable<ISuperman>, ISuperman[]>();
container.Resolve<MainViewModel>();
在上面的代码中,我们得到了所有继承自 BaseClass
,然后构造一个类型超人< / code>并将其映射到
。 RegisterTypes调用将相当于为每个BaseClass调用RegisterType: ISuperman
code> BaseClass的
In the above code we get all classes that inherit from BaseClass
and then construct a type Superman<>
and map that to ISuperman
using the name of the BaseClass
. The RegisterTypes call will be equivalent to calling RegisterType for every BaseClass:
container.RegisterType<ISuperman, Superman<ClassNumber001>("ClassNumber001");
container.RegisterType<ISuperman, Superman<ClassNumber002>("ClassNumber002");
然后当> MainViewModel
被解析时,它迭代所有 ISuperman
实例并调用一个打印输出的方法:
Then when MainViewModel
is resolved it iterates over all ISuperman
instances and calls a method which prints out:
001 Foo >
002 Foo
001 Foo
002 Foo
显示我们注入了2 ISuperman
实例:超人< ClassNumber001>
和超人< ClassNumber002>
。
showing that we injected 2 ISuperman
instances: Superman<ClassNumber001>
and Superman<ClassNumber002>
.
如果您需要针对BaseClasses的特定注册(例如非默认生命期管理器),那么您也可以按照惯例使用注册来注册这些)
If you need specific registrations for the BaseClasses (e.g. non-default lifetime manager) then you can use registration by convention to register those too).
这篇关于我如何动态地注册具有Unity名称的泛型类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!