如何在Unity中动态注册具有名称的泛型类?
本文关键字:有名称 泛型类 注册 动态 Unity | 更新日期: 2023-09-27 18:02:44
我有一个具有BaseClass的大量类(300+)的汇编,我想注册一个具有接口的泛型类。
如果你想解析一个接口的对象数组,你必须通过{Name}注册。我想要一个对象的数组在MainViewModel自动。
是否有一种方法可以自动使用反射?有什么建议吗?
(伪)例子:
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)
{
}
手工示例:
container.RegisterType<ISuperman, Superman <ClassNumber001>>("ClassNumber001");
container.RegisterType<ISuperman, Superman <ClassNumber002>>("ClassNumber002");
container.RegisterType<IEnumerable<ISuperman>, ISuperman[]>();
这是我想到的可能对你有用的东西…
你可以像下面这样注册类型,并且应该适用于开放泛型。
container.RegisterType(typeof(ISuperman<>), typeof(Superman<>), ... );
注册泛型参数和类型
希望这对你有帮助!
是的,您需要使用反射来轻松地创建您想要的所有映射。因为你使用的是Unity 3,你可以利用Registration by Convention来提供注册类的帮助。
我把你的伪代码翻译成真实的代码:
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();
}
}
}
然后按照约定使用注册来注册所有泛型:
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
继承的所有类,然后构造了一个类型Superman<>
,并使用BaseClass
的名称将其映射到ISuperman
。RegisterTypes调用将等同于为每个BaseClass调用RegisterType:
container.RegisterType<ISuperman, Superman<ClassNumber001>("ClassNumber001");
container.RegisterType<ISuperman, Superman<ClassNumber002>("ClassNumber002");
然后当MainViewModel
被解析时,它遍历所有ISuperman
实例并调用一个方法,输出:
001 Foo
002年Foo
表明我们注入了2个ISuperman
实例:Superman<ClassNumber001>
和Superman<ClassNumber002>
。
如果你需要为baseclass进行特定的注册(例如,非默认的生命周期管理器),那么你也可以使用约定注册来注册它们。
有一些方法可以做到这一点。一种是使用定义类型的XML,比如MyClass和IMyClass,在运行时它根据可用的程序集进行解析。但在我看来,更好的方法是创建一个项目,你可以将加载依赖项的责任委托给它。
假设你创建了一个这样的类:
public class MyClass : IMyClass
{
private readonly IUnityContainer _container;
#ctor
// initialie the container through the constructor
public void DoWork<Interface, Class>() where Class: Interface
{
_container.RegisterType<Interface, Class>(
//TODO: You can setup the container lifecycle which can be transient
// or singleton or custom based on your project requirement
)
}
}
现在,任何需要注册自己的人都可以调用这个接口IMyClass来在容器中注册自己,并且可以将依赖项注入到需要执行该任务的任何类中。