具有逆变类型参数和 Unity 容器的泛型

Posted

技术标签:

【中文标题】具有逆变类型参数和 Unity 容器的泛型【英文标题】:Generics with contravariant type parameters and Unity container 【发布时间】:2013-05-19 07:06:50 【问题描述】:

我有一个带逆变类型参数的接口,比如IFoo:

interface IFoo<in T> 

现在我有三个班级:

class B 

class D : B 

class Foo : IFoo<B> 

如果我这样注册他们

container.RegisterType<IFoo<B>, Foo>();

...然后尝试解析IFoo&lt;D&gt;,它失败了,因为我没有真正注册IFoo&lt;D&gt;IFoo&lt;&gt; .天气晴朗。

我当前的解决方案只是遍历Registrations,找到RegisteredType 可从解析类型(在我的情况下为IFoo&lt;D&gt;)分配的注册,然后解析其MappedToType 类型。

问题很简单:有没有更好的方法来做到这一点?任何建议将不胜感激。

谢谢。

编辑:

更多上下文。

我有某种映射器。

IMapper<in TSource, in TDest> : IMapper // IMapper is non-generic

    void Map(TSource source, TDest dest);

我只想注册基本映射器(其中TSourceIEnumerable&lt;T&gt;),并且能够为实现IEnumerable&lt;T&gt; 的每种类型解析此映射器,例如T[]

object source = GetSource(); // runtime type is T[]
object dest = GetDest();

Type mapperType = typeof(IMapper<,>).MakeGenericType(source.GetType(), dest.GetType());
IMapper mapper = (IMapper) container.Resolve(mapperType);
mapper.Map(source, dest);

是的,我只对基于 Unity/C# 的方法感兴趣...

【问题讨论】:

也许更好的方法是实现一个注册 BuilderStrategy 的 Unity 扩展。 切换到不同的框架? 你为什么要尝试解析 IFoo 而不注册它?注册或解析是否是动态的? @WiktorZychla:你只想注册 IFoo 以一次注册所有类型的子类。将来您可能会有其他子类,并且您希望它能够开箱即用。它还保存了要注册的课程数量。 @WiktorZychla:在某些情况下这是有道理的(尽管很少见)。但是使用IEventHandler&lt;TEvent&gt; 或在使用版本化消息进行消息传递以实现向后兼容性时,会想到处理业务事件。 【参考方案1】:

听起来您每次都想解析同一个 Mapper。如果这是正确的,并且 IEnumerable 是您的映射器需要处理的唯一接口,那么您的方法似乎有点矫枉过正。

我会尝试使用非通用IEnumerable() 注册映射器,而不是IEnumerable&lt;T&gt; (container.RegisterType&lt;IFoo&lt;IEnumerable&gt;, Foo&gt;();)。如果我没记错的话,一个泛型的IEnumerable&lt;T&gt; 可以传递给一个非泛型的IEnumerable() 参数,所以你不必担心传递的是什么类型的参数。所以当你去解析你的映射器时,你甚至不需要检查类型,只需解析IMapper&lt;IEnumerable&gt;

编译如下代码:

[TestClass]
    public class UnitTest1
    
        [TestMethod]
        public void TestMethod1()
                    
            IEnumerable<int> coll = new int[0];
            IEnumerable coll2 = coll;

         var blah = new Test<IEnumerable<int>>();
    


public interface ITest<in T> where T : IEnumerable



public class Test<T> : ITest<T> where T : IEnumerable  

如果您需要获得IMapper 的不同实现,那就另当别论了。在这种情况下,您必须注册每个实现。

【讨论】:

以上是关于具有逆变类型参数和 Unity 容器的泛型的主要内容,如果未能解决你的问题,请参考以下文章

GetMethod 的 Type[] 以获取具有两个参数和一个类型参数的泛型方法

TypeScript 中具有泛型类型参数的泛型类型的替代方案

建造者模式-具有递归类型参数的泛型类型(Effective-Java)

Scala的泛型

在具有泛型参数的泛型方法中使用 Spring RestTemplate

Kotlin泛型总结 ★ ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 | 可变参数结合泛型 | out 协变 | in 逆变 | reified 检查泛型参数类型 )