2009-05-12 3 views
7

У меня есть экземпляр, который реализует IDictionary<T, K>, я не знаю T и K в compiletime и хочу получить из него все элементы. По какой-то причине я не хочу использовать 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

Я не уверен, что я понимаю вопрос. Вы хотите использовать оператор [] вместо получения значения свойства Item через Reflection? – Andy

+0

Пробовал это с помощью словаря , и попытка использовать indexer/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

Ahh, я никогда не видел этот инициализатор хэш-таблицы раньше! +1 – leppie

+0

@ Leppie - это часть синтаксиса инициализатора коллекции; вы можете использовать любой метод Add, но если он принимает несколько аргументов, вы переносите дополнительный набор фигурных скобок. Итак, {123, «abc»} вызывает .Add (123, «abc») –

+0

Очень приятно. Существует одна проблема: iType.GetGenericArguments() может выйти из строя, потому что конкретный тип сам по себе не должен иметь те же общие аргументы, что и IDictionary, который он реализует. Но у меня есть код для получения правильных типов уже в вопросе. –

4

Просто для завершения, даже если решение Marc Gravell является гораздо лучше, это так, как она работает так, как я уже начал:

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

Это вызывает оператор [] словаря.

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