与输入和输出的Co / Contra-Variance

时间:2010-07-21 19:55:31

标签: c# c#-4.0

我有co / contra-variance的问题。我知道你不能同时拥有输入和输出。所以这是一个简单的例子:

public interface A<T>
{
    T Object {get;set;}
}

public interface B
{
    // Some stuff
}

public class BImplementor : B
{ }

public class Implementor : A<BImplementor> {}

假设你有这些类,我想写一个像这样的方法

public void Command(B obj)
{
    var a = (A<B>)Unity.Resolve(typeof(A<>).MakeGenericType(obj.GetType());
    a.Object = obj;
}

我正在使用Unity来解析A B的具体实现者Implementor,但我所知道的只是A<B> }。我不知道直接这样做的方法,我不认为它实际上是可能的,但有没有人知道一个解决方法来模拟我正在尝试做的事情。

1 个答案:

答案 0 :(得分:0)

正如您所说,您不能同时拥有输入和输出,因此我们将A<T>更改为A<in T>,以便Command可以将obj分配给Object属性:

public interface A<in T>
{
    void SetObject(T obj);
}

public interface B { }

public class BImplementor : B { }

public class Implementor : A<BImplementor>
{
    public void SetObject(BImplementor t) { ... }
}

Command方法实际上是这样做的:

public void Command(B obj)
{
    A<B> a = (A<B>)new Implementor();
    a.SetObject(obj);
}

但此演员表永远不会成功,因为A<B>.SetObject必须接受任何B作为输入,而Implementor.SetObject仅接受BImplementor个对象作为输入!


由于您现在只能将BImplementor传递给A<B>.SetObject,因此您可以使用反射来解决问题。

解决方法1:

public void Command1(B obj)
{
    object a = Unity.Resolve(typeof(A<>).MakeGenericType(obj.GetType());
    a.GetType().GetMethod("SetObject").Invoke(a, new object[] { obj });
}

解决方法2:

public void Command(B obj)
{
    this.GetType()
        .GetMethod("Command2")
        .MakeGenericMethod(obj.GetType())
        .Invoke(this, new object[] { obj });
}

public void Command2<T>(T obj) where T : B
{
    A<T> a = Unity.Resolve<A<T>>();
    a.SetObject(obj);
}