2012-03-01 14 views
0

私はその後、私はどんなMyTypeをとるコントローラを持っています。このコード未知のジェネリック型を扱う方法はありますか?

public interface IConsumable<T> { 
    void Consume(T item); 
} 

public interface IProducer<T> { 
    IConsumable<T> Consumer { get; set; } 
    void Produce(); 
} 

public class MyClass : MyType, 
    IConsumable<ISpecifcItem> 
{ 
    public void Consume(ISpecificItem item) { ... } 
} 

public class MySpecificItemProducer 
    : IProducer<ISpecificItem> { 
    public IConsumable<ISpecificItem> Consumer { get; set; } 
    public void Produce() { 
    ISpecificItem myItem = new MyVerySpecificItem(); 
    Consumer.Consume(myItem); 
    } 
} 

を持って、それがジェネリック型パラメータの種類を実装し、取得することIConsumable<>のすべてのタイプを検出します。このタイプのリストでは、IProducer<TParam>を実装するすべてのプロデューサが検出されます。それは難しくありません:

var consumerTypes = 
    myType.GetType().GetInterfaces() 
    .Where(x => x.IsGenericType) 
    .Where(x => x.GetGenericTypeDefinition() == 
     typeof(IConsumable<>)); 

    if (consumerTypes.Any()) { 
    var instanceTypes = consumerTypes 
     .Select(x => x.GetGenericArguments().First()) 
     .Select(x => typeof(IProducer<>).MakeGenericType(x)); 
    // for each of those types discover classes where 
    // it assignable from 
    // and instantiate the class using the Activator 
    } 

しかし、問題は、私はどのようにプロデューサーのコンシューマープロパティを設定するのですか?プロデューサのインスタンスは私にとってはオブジェクトなので、変数のようにTを使うことができないので、IProducer<T>にキャストできません。

私は反射でそれを行うことができますproducerInstance.GetType().GetProperty("Consumer").SetValue(producerInstance, consumerInstance, null);しかし、別の方法があるかどうかを知りたかったですか?

興味深いことに、これは実行時に失敗しました:それはconsumerInstanceのタイプは、プロパティの型に互換性がなかったと訴え

MyClass consumerInstance; 
dynamic test = producerInstance; 
test.Consumer = consumerInstance; 

EDIT:consumerInstanceも例えば、ダイナミックだったときの動的例にのみ働いた:

dynamic testC = consumerInstance; 
dynamic testP = producerInstance; 
testP.Consumer = testC; 
+0

動的コードがうまく動作します。 – Ani

+0

ええええええええええええええええええええええええええええええええええええええええええええええええと、 – Andreas

+0

私は動的サンプルをフォローし、譲受人を動的にしたときにそれが働いていることを発見しました。 – Andreas

答えて

5

残念ながら、あなたが提供されたコードをリファクタリングすることなく、あなたは(あなたが行ったように)より反射せずに問題を解決することはできません。ただし、コンシューマプロパティを設定する前にリフレクションを使用すると、読みやすくなります。

var method = GetType().GetMethod("Process"); 
var genericType = interfaceType.GetGenericArguments().First(); 
var invocable = method.MakeGenericMethod(genericType); 

invocable.Invoke(this, new object[] { producer, consumer }); 

public void Process<T>(IProducer<T> producer, IConsumable<T> consumer) 
{ 
    producer.Consumer = consumer; 
} 

MyTypeに1を超えるIConsumableを与え、ジェネリック型引数を変更するだけですか?私はあなたがそれらのインターフェースのリストを取得しているからだと思います。私はあなたのプロデューサーをどこから得るのかはわかりませんが、リフレクションを使わない唯一の方法は、それを避けることです。各MyTypeに、プロデューサのリストを '設定'するメソッドを提供するように強制することも考えられます(MyTypeは内部的にすべての型を自分自身が知っている)。あなたは次の操作を実行する必要があります(がMyTypeの内部または外部)から生産を引く場所に応じて:

public interface IProducer { } 

public interface IProducer<T> : IProducer 
{ 
    IConsumable<T> Consumer { get; set; } 
    void Produce(); 
} 

public interface IConsumableProvider 
{ 
    void SetupProducers(params IProducer[] producers); 
} 

public class MyType : 
    IConsumable<int>, 
    IConsumable<double>, 
    IConsumableProvider 
{ 
    public void Consume(int item) 
    { 
    throw new NotImplementedException(); 
    } 

    public void Consume(double item) 
    { 
    throw new NotImplementedException(); 
    } 

    public void SetupProducers(params IProducer[] producers) 
    { 
    (producers[0] as IProducer<int>).Consumer = (this as IConsumable<int>); 
    (producers[1] as IProducer<double>).Consumer = (this as IConsumable<double>); 
    } 
} 

私は解決策と恋にないんだけど、私は最適解はより多くの情報を必要とする感じあなたの現在のコードベースについて - あなたがすでに持っているものとは多すぎる答えを与えるでしょう。

+0

おかげさまで、正直言って私は反射の少ないソリューションを以前にも持っていましたが、そのためには、非ジェネリックインターフェイスが必要で、一部のキャスティングが必要でした。それは私がそこにいるのが好きではなかったインタフェースにいくつかのメソッドを追加しました。 – Andreas

+0

私は同じクラスに文字列参照とそのように参照されたメソッドを配置するので、何らかの方法であなたのソリューションを好きです。あなたが言っているようにセットアップするのはちょっと複雑ですが、これは私をもっと安全に感じさせます。誰かがプロパティ名をリファクタリングすると、変更は自動的に転送されます。 – Andreas

+0

クール、これは助けてうれしいです!アップヴォートを手に入れますか? :) – payo

関連する問題