如何使用Unity的名称动态注册generics类?
我有一个包含很多类(300+)和BaseClass的程序集,我希望注册一个带接口的generics类。
如果要解析接口的对象数组,则必须通过{ Name }注册。 我想自动在MainViewModel中有一个对象数组。
有没有办法用reflection自动化这个? 有什么建议?
示例(伪):
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 lotsofSuperman) { }
手工实例:
container.RegisterType<ISuperman, Superman >("ClassNumber001"); container.RegisterType<ISuperman, Superman >("ClassNumber002"); container.RegisterType<IEnumerable, ISuperman[]>();
这是我想到的可能对你有用的东西……
您可以按如下方式注册类型,并且应该适用于开放式generics 。
container.RegisterType(typeof(ISuperman<>), typeof(Superman<>), ... );
注册通用参数和类型
希望这可以帮助!
是的,您需要使用reflection来轻松创建所需的所有映射。 由于您使用的是Unity 3,因此您可以利用“按惯例注册”在注册课程时提供帮助(更重的提升)。
我已经把你的伪代码翻译成真正的代码:
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 : 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 lotsofSuperman) { foreach(ISuperman superman in lotsofSuperman) { superman.Do(); } } }
然后按惯例使用注册来注册所有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, ISuperman[]>(); container.Resolve();
在上面的代码中,我们获得了从BaseClass
inheritance的所有类,然后构造了一个类型Superman<>
并使用BaseClass
的名称将其映射到ISuperman
。 RegisterTypes调用相当于为每个BaseClass调用RegisterType:
container.RegisterType("ClassNumber001"); container.RegisterType("ClassNumber002");
然后,当MainViewModel
被解析时,它遍历所有ISuperman
实例并调用打印出来的方法:
001 Foo
002 Foo
显示我们注入了2个ISuperman
实例: Superman
和Superman
。
如果您需要BaseClasses的特定注册(例如非默认生命周期管理器),那么您可以按惯例使用注册来注册那些)。
有一些方法可以做到这一点。 一种是使用XML,其中定义了类型,例如MyClass和IMyClass,并且在运行时它根据可用的程序集解析。 但在我看来,更好的方法是创建一个项目,您可以委派加载依赖项的责任。
让我们说你创建一个这样的类:
public class MyClass : IMyClass { private readonly IUnityContainer _container; #ctor // initialie the container through the constructor public void DoWork() where Class: Interface { _container.RegisterType( //TODO: You can setup the container lifecycle which can be transient // or singleton or custom based on your project requirement ) } }
现在,无论谁需要注册自己,都可以调用此接口IMyClass来使自己在容器中注册,并且可以将依赖项注入到执行该任务的任何类中。