【问题标题】:Generics with contravariant type parameters and Unity container具有逆变类型参数和 Unity 容器的泛型
【发布时间】: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; 或在使用版本化消息进行消息传递以实现向后兼容性时,会想到处理业务事件。

标签: c# .net generics dependency-injection unity-container


【解决方案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 的不同实现,那就另当别论了。在这种情况下,您必须注册每个实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    相关资源
    最近更新 更多