2016-08-05 2 views
1

Ich habe einen Verweis auf ein Objekt. Ich weiß, es passt sich anSchlüssel und Werte von IDictionary aufzählen, wenn ich den Typ der Werte nicht kenne

IDictionary<string, T> 

für irgendeine Art T. (Es kann nicht in einfachen IDictionary entsprechen, oder zu IReadyOnlyDictionary). Alles, was ich über T weiß, ist, dass es vom Objekt abstammt. Wie kann ich seine Schlüssel erhalten und den Wert für einen Schlüssel erhalten? (Ich bin damit einverstanden, dass der Wert als ein Objekt zurückgegeben wird, nicht als ein T. Ich bin auch gut damit, nie zu lernen, was T ist.)

Was ich schreiben möchte, aber nicht kann, ist so etwas :

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

**

pro Anfrage, unten ist eine Beispielklasse.

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

Haben Sie versucht, die Methode generisch zu machen? Etwas wie 'SomeMethod (IDictionary reallyADict)'? –

+0

Ich habe einen Verweis auf wirklichADict als ein Objekt, nicht als ein Wörterbuch . –

+0

Mögliches Duplikat von http://stackoverflow.com/questions/141088/what-is-the-best-way-to-iterate-over-a-ictionary-in-c – Sherlock

Antwort

6

Leider können Sie nicht den reallyADict so etwas wie Dictionary<string,T> werfen, weil Sie eine bestimmte Art benötigen.

Und Manfred Kommentar zu einer generischen Methode wie

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

meinen Ansatz zu verwenden, auch wäre. Aber Sie haben angegeben, dass Sie wirklich nur das Wörterbuch als object haben.

So löste ich dies mit Reflexion:

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

dieser Methode wird die Keys Eigenschaft aus dem reallyDict wird (falls vorhanden) und verwendet sie als IEnumerable<string>.

Dann iteriert es über alle diese Schlüssel und verwendet die Indexer-Eigenschaft des zugrunde liegenden Wörterbuchs, um den Wert zurückzugeben. Die Indexer-Eigenschaft hat den Namen Item.

+1

@ManfreedRadlwimmer Nr. "GetMethod" ist eine Eigenschaft einer 'PropertyInfo'. Es ist die 'MethodInfo', die den Getter dieser Eigenschaft darstellt. In dieser Zeile möchte ich nicht den getter (ich habe es bereits in 'GetMethod'), ich will nur _ diesen Getter _invoke_. –

+0

Wenn Sie eine ältere .NET Version verwenden, können Sie 'GetGetMethod()' anstelle von 'GetMethod' verwenden (verfügbar seit 4.5) –

+1

@ManfredRadlwimmer hat es nur überprüft, ja,' GetGetMethod() 'würde' MethodInfo' für zurückgeben der Getter, aber "GetMethod" ist nur eine Eigenschaft, die das gleiche zurückgibt. Sie können wählen, wie Sie möchten;) –

Verwandte Themen