Co / Contra-Variance с входом и выходом - PullRequest
2 голосов
/ 21 июля 2010

У меня проблема с ко / противоречивостью.Я понимаю, что вы не можете иметь и вход, и выход.Вот простой пример:

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 голосов
/ 22 июля 2010

Как вы сказали, у вас не может быть и входа, и выхода, поэтому давайте изменим 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...