开发者

Co/Contra-Variance with input and output

开发者 https://www.devze.com 2023-01-08 12:50 出处:网络
I have an issue with co/contra-variance.I understand you can\'t have both input and output.So here is a simple example:

I have an issue with co/contra-variance. I understand you can't have both input and output. So here is a simple example:

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

public interface B
{
    // Some stuff
}

public class BImplementor : B
{ }

public class Implementor : A<BImplementor> {}

Suppose you have these classes and I'm wanting to write a method like this

public void Command(B obj)
{
    var a = (A<B>)Unity.Resolve(typeof(A<>).MakeGenericType(obj.GetType());
    a.Ob开发者_如何学Goject = obj;
}

I'm using Unity to resolve a A of the specifc implementor of B (specifically Implementor), but all I know about it is that it is an A<B>. I don't know of a way to do this directly and I don't think it is actually possible, but does anyone know of a workaround to simulate what I'm trying to do.


As you said, you cannot have both input and output, so let's change A<T> to A<in T> so Command can assign obj to the Object property:

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) { ... }
}

The Command method essentially does this:

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

But this cast can never succeed, because A<B>.SetObject must accept any B as input, while Implementor.SetObject accepts only BImplementor objects as input!


Since you now that you'll only ever pass a BImplementor to A<B>.SetObject, you can work around the problem using reflection.

Workaround 1:

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

Workaround 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);
}
0

精彩评论

暂无评论...
验证码 换一张
取 消