如何在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[]>();

如何在Unity中动态注册具有名称的泛型类?

这是我想到的可能对你有用的东西…

你可以像下面这样注册类型,并且应该适用于开放泛型。

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来在容器中注册自己,并且可以将依赖项注入到需要执行该任务的任何类中。