2016-08-05 4 views
1

У меня есть ссылка на объект. Я знаю, что это соответствуетПеречислять ключи и значения IDictionary, когда я не знаю тип значений

IDictionary<string, T> 

для некоторого типа T. (Он может не соответствовать обычной IDictionary или IReadyOnlyDictionary). Все, что я знаю о Т, это то, что он сходит с объекта. Как я могу получить его ключи и получить значение для ключа? (Я в порядке, когда значение возвращается как объект, а не как T. Я тоже прекрасно разбираюсь в том, что такое T.)

Что я хочу написать, но не могу, это что-то вроде этого :

public void SomeMethod(object reallyADict) { // reallyADict implements IDictionary<string, T>. 
    foreach (string key in reallyADict.Keys) { 
    object value = reallyADict[key]; 
    // . . . 
    } 
} 

**

По желанию, класс образец ниже.

using System; 
using System.Collections.Generic; 
using System.Collections; 

namespace My.Collections 
{ 
    public class WrappedDictionary: IDictionary<string, int> 
    { 
    public WrappedDictionary() { 
     this.InnerDictionary = new Dictionary<string, int>{ {"one", 1}, {"two", 2 }}; 
    } 
    private Dictionary<string, int> InnerDictionary { get; set;} 

    private ICollection<KeyValuePair<string, int>> InnerCollection { 
     get { 
     return this.InnerDictionary; 
     } 
    } 


    #region IDictionary implementation 
    void IDictionary<string, int>.Add(string key, int value) { 
     this.InnerDictionary.Add(key, value); 
    } 
    bool IDictionary<string, int>.ContainsKey(string key) { 
     return this.InnerDictionary.ContainsKey(key); 
    } 
    bool IDictionary<string, int>.Remove(string key) { 
     return this.InnerDictionary.Remove(key); 
    } 
    bool IDictionary<string, int>.TryGetValue(string key, out int value) { 
     return this.InnerDictionary.TryGetValue(key, out value); 
    } 
    int IDictionary<string, int>.this[string index] { 
     get { 
     return this.InnerDictionary[index]; 
     } 
     set { 
     this.InnerDictionary[index] = value; 
     } 
    } 
    ICollection<string> IDictionary<string, int>.Keys { 
     get { 
     return this.InnerDictionary.Keys; 
     } 
    } 
    ICollection<int> IDictionary<string, int>.Values { 
     get { 
     return this.InnerDictionary.Values; 
     } 
    } 
    #endregion 
    #region ICollection implementation 
    void ICollection<KeyValuePair<string, int>>.Add(KeyValuePair<string, int> item) { 
     this.InnerCollection.Add(item); 
    } 
    void ICollection<KeyValuePair<string, int>>.Clear() { 
     this.InnerDictionary.Clear(); 
    } 
    bool ICollection<KeyValuePair<string, int>>.Contains(KeyValuePair<string, int> item) { 
     return this.InnerCollection.Contains(item); 
    } 
    void ICollection<KeyValuePair<string, int>>.CopyTo(KeyValuePair<string, int>[] array, int arrayIndex) { 
     this.InnerCollection.CopyTo(array, arrayIndex); 
    } 
    bool ICollection<KeyValuePair<string, int>>.Remove(KeyValuePair<string, int> item) { 
     return this.InnerCollection.Remove(item); 
    } 
    int ICollection<KeyValuePair<string, int>>.Count { 
     get { 
     return this.InnerCollection.Count; 
     } 
    } 
    bool ICollection<KeyValuePair<string, int>>.IsReadOnly { 
     get { 
     return this.InnerCollection.IsReadOnly; 
     } 
    } 
    #endregion 
    #region IEnumerable implementation 
    IEnumerator<KeyValuePair<string, int>> IEnumerable<KeyValuePair<string, int>>.GetEnumerator() { 
     return this.InnerCollection.GetEnumerator(); 
    } 
    #endregion 
    #region IEnumerable implementation 
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { 
     return (this as IEnumerable).GetEnumerator(); 
    } 
    #endregion 
    } 
} 
+0

Вы пробовали сделать общий метод? Что-то вроде 'SomeMethod (IDictionary reallyADict)'? –

+0

У меня есть ссылка на reallyADict как объект, а не как словарь . –

+0

Возможный дубликат http://stackoverflow.com/questions/141088/what-is-the-best-way-to-iterate-over-a-dictionary-in-c – Sherlock

ответ

6

Unfortunatly вы не можете бросить reallyADict к чему-то вроде Dictionary<string,T>, потому что вам нужен конкретный тип.

И комментарий Манфреда использовать общий метод, как

public IEnumerable<T> SomeMethod<T>(Dictionary<string, T> dict) 

бы мой подход тоже. Но вы заявили, что у вас действительно есть только словарь: object.

Так что я решил это с отражением:

public IEnumerable<object> SomeMethod(object reallyADict) 
{ 
    Type genericInterface = reallyADict?.GetType().GetInterface("IDictionary`2"); 

    PropertyInfo propKeys = genericInterface?.GetProperty("Keys"); 
    if (propKeys?.GetMethod == null) yield break; 

    IEnumerable<string> keys = (IEnumerable<string>)propKeys.GetValue(reallyADict); 

    PropertyInfo propIndex = genericInterface.GetProperty("Item"); 
    if (propIndex?.GetMethod == null) yield break; 

    foreach (string key in keys) 
     yield return propIndex.GetMethod.Invoke(reallyADict, new object[] { key }); 
} 

Этот метод получает Keys свойство из reallyDict (если есть) и использует его в качестве IEnumerable<string>.

Затем он выполняет итерацию по всем этим клавишам и использует свойство индексатора базового словаря для возврата значения. Свойство indexer имеет имя Item.

+1

@ManfredRadlwimmer No. 'GetMethod' - свойство 'PropertyInfo'. Это 'MethodInfo', который представляет собой getter этого свойства. В этой строке я не хочу _get_ getter (у меня уже есть это в 'GetMethod'), я просто хочу _invoke_ этот getter. –

+0

Если вы используете более старую версию .NET, вы можете использовать 'GetGetMethod()' вместо 'GetMethod' (доступно с 4.5) –

+1

@ManfredRadlwimmer только что проверил его, да,' GetGetMethod() 'вернет' MethodInfo' для getter, но 'GetMethod' - это просто свойство, которое возвращает то же самое. Вы можете выбрать, как вам нравится;) –

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

  • Нет связанных вопросов^_^