2010-07-21 1 views
2

У меня проблема с co/contra-variance. Я понимаю, что вы не можете иметь вход и выход. Так вот простой пример: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 в Implementor, специфические от B (в частности, Implementor), но все, что я знаю об этом, это то, что это A<B>. Я не знаю, как это сделать напрямую, и я не думаю, что это действительно возможно, но кто-нибудь знает об обходном пути, чтобы имитировать то, что я пытаюсь сделать.

ответ

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

Я знаю, что это так. К сожалению, я, как написано, действительно безопасен по типу, потому что я знаю, что Unity вернет объект типа 'A ', но без переключения на все возможные типы, которые я не знаю о способе чтобы привести его к правильному типу. Я надеялся, что у кого-то появится идея обходного пути. Моя конечная цель - использовать Unity для разрешения 'A' любого конкретного типа, передаваемого в Command. – Stephan

+0

@Stephan: Как насчет какого-то грязного отражения? 'object a = Unity.Resolve (...); a.GetType(). GetMethod («SetObject»). Invoke (a, new object [] {obj}); ' – dtb

+0

Я боялся, что это был ответ, который я собирался получить. Хотя это сработает, это был бы последний вариант, если бы у кого-то не было других возможностей для реструктуризации. Спасибо за предложение. – Stephan

Смежные вопросы