Unity:为两个接口注册相同类型

6

我将在Unity容器中看到一种奇怪的行为,当使用两个接口时,它们都注册到同一个装饰器。通过以下代码示例更清晰。

我有以下类层次结构:

   public interface IBaseInterface
    {

    }

    public interface IInterface1: IBaseInterface
    {

    }
    public interface IInterface2: IBaseInterface
    {

    }
    public class Interface1Impl : IInterface1
    {
    }
    public class Interface2Impl : IInterface2
    {
    }

    public class BaseInterfaceDecorator: IInterface1,IInterface2
    {
        private readonly IBaseInterface baseInterface;

        public BaseInterfaceDecorator(IBaseInterface baseInterface)
        {
            this.baseInterface = baseInterface;
        }
    }

    public class MyClass
    {
        private readonly IInterface1 interface1;

        public MyClass(IInterface1 interface1)
        {
            this.interface1 = interface1;
        }            
    }

这是注册码:

var container = new UnityContainer();           
        container.RegisterType<IInterface1, BaseInterfaceDecorator>(
            new InjectionConstructor(
                new ResolvedParameter<Interface1Impl>()));

        container.RegisterType<IInterface2, BaseInterfaceDecorator>(
           new InjectionConstructor(
               new ResolvedParameter<Interface2Impl>()));


        var dependency = container.Resolve<MyClass>();

当解析 MyClass 时,我得到的是一个带有 Interface2Impl 的 BaseInterfaceDecorator 而不是 Interface1Impl。这对我来说很奇怪。你能解释一下吗?
2个回答

9
似乎对于给定的 "to" 类型,最后一个注入指令会胜出。如果你获取 Reflector 的副本,并查看 UnityContainer.RegisterType(Type, Type, string, LifetimeManager, InjectionMember[]) 实现,你就会明白为什么了。
在我看来,这种行为是一个 bug。至少,InjectedMembers.ConfigureInjectionFor(Type, string, InjectionMember[]) 应该抛出异常,而不是默默地替换之前的注入配置。然而,它确实应该支持你正在尝试的内容。

如果读者不清楚的话,Unity在内部缓存了“to”类型的构建键(例如泛型签名中的“TTo”)。下一次解析任何“TFrom”类型时,将使用“TTo”的构建键来执行构建。此构建键还与生命周期管理器相关联,因此Unity似乎对于所有后续解析TTo(无论TFrom的身份如何),都使用第一个使用的生命周期管理器(在Build Up中)。这是Unity Build Keys的错误。解决方法是使用命名注册,这破坏了建立协变类型标识的目的。 - Shaun Wilson

2

我不知道这是否有帮助。现在对你来说可能已经太晚了。但是,如果您使用命名注册,即将每个要解析的类型注册为不同的名称,则可以实现此目标。

例如:

Container.RegisterType<IInterface1, BaseInterfaceDecorator>("interface1");
Container.RegisterType<IInterface2, BaseInterfaceDecorator>("interface2");

这是一个有效的解决方法,但它违背了在注册中使用协变类型的目的。Unity假设所有对'TTo'的解析都指向创建TTo实例的相同配置/指令。因此,在注入参数和生命周期管理方面,您将会看到问题,其中TFrom的身份应该导致不同的行为(不同的注入参数、不同的生命周期管理器等)。 - Shaun Wilson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接