2009-05-12 20 views
7

私はIDictionary<T, K>を実装するインスタンスを持っています。私はコンパイル時にTとKを知らず、そこからすべての要素を取得したいと思います。何らかの理由でIEnumerableを使用したくない場合は、IDictionaryで実装されている唯一の非ジェネリックインターフェイスです。私がこれまで持って反射を使って汎用IDictionaryの値を取得する

コード:

// getting types 
Type iDictType = instance.GetType().GetInterface("IDictionary`2"); 
Type keyType = iDictType.GetGenericArguments()[0]; 
Type valueType = iDictType.GetGenericArguments()[1]; 

// getting the keys 
IEnumerable keys = (IEnumerable)dictType.GetProperty("Keys") 
    .GetValue(instance, null); 

foreach (object key in keys) 
{ 
    // ==> this does not work: calling the [] operator 
    object value = dictType.GetProperty("Item") 
    .GetValue(instance, new object[] {key }); 


    // getting the value from another instance with TryGet 
    MethodInfo tryGetValue = iDictType.GetMethod("TryGetValue"); 
    object[] arguments = new object[] { key, null }; 
    bool hasElement = (bool)tryGetValue.Invoke(otherInstance, arguments); 
    object anotherValue = arguments[1]; 
} 

は、私はまた、TryGetValueを呼び出すことができますが、私は[]演算子を呼び出すことが可能であるべきだと思います。誰か助けてくれますか?

+0

私は質問を理解しているかどうかはわかりません。 Reflectionを介してItemプロパティの値を取得する代わりに、[]演算子を使用しますか? – Andy

+0

ディクショナリでこれを試し、インデクサ/ get_Itemの使用を試みました。 – Gishu

+0

@Andy:[]演算子は、実行時にItemプロパティを実際に呼び出します。これはコンパイル時には表示されません。 @ Gishu:どのようにインデクサーに電話しましたか?プロパティ 'Item'はありません。メソッド 'get_Item'だけですか? –

答えて

21

それはTKey/TValueアウト図に良くなる、とMakeGenericMethod経由で定期的なコードに切り替えるだろう - そうのように:

編集 - あなたも引数としてotherInstanceに渡すことができ、場合彼らは

static class Program 
{ 
    static void Main() 
    { 
     object obj = new Dictionary<int, string> { 
      { 123, "abc" }, { 456, "def" } }; 

     foreach (Type iType in obj.GetType().GetInterfaces()) 
     { 
      if (iType.IsGenericType && iType.GetGenericTypeDefinition() 
       == typeof(IDictionary<,>)) 
      { 
       typeof(Program).GetMethod("ShowContents") 
        .MakeGenericMethod(iType.GetGenericArguments()) 
        .Invoke(null, new object[] { obj }); 
       break; 
      } 
     } 
    } 
    public static void ShowContents<TKey, TValue>(
     IDictionary<TKey, TValue> data) 
    { 
     foreach (var pair in data) 
     { 
      Console.WriteLine(pair.Key + " = " + pair.Value); 
     } 
    }  
} 
+0

ああ、ハッシュテーブルのイニシャライザを見たことはありません! +1 – leppie

+0

@Leppie - コレクションの初期化構文の一部です。任意のAddメソッドを使用できますが、複数の引数をとる場合は、追加の中カッコで囲みます。したがって、{123、 "abc"}は.Add(123、 "abc")を呼び出します。 –

+0

とてもいいです。 1つの問題があります。具体的な型自体が実装するIDictionaryと同じ汎用引数を持つ必要がないため、iType.GetGenericArguments()は失敗する可能性があります。しかし、私はすでに質問に正しいタイプを取得するコードを持っています。 –

4

だけで完成のためには、マルクGravellのソリューションは非常に良くなっても、これはそれは私がすでに開始方法をどのように働くかの方法である)同じタイプのものである:

object value = dictType.GetMethod("get_Item") 
    .Invoke(instance, new object[] { key }); 

これは、辞書の[]演算子を呼び出します。

関連する問題