2008-09-23 12 views
14

Gibt es eine Möglichkeit zu testen, ob ein Objekt ein Wörterbuch ist?Testen, ob ein Objekt ein Dictionary in C ist

In einer Methode versuche ich, einen Wert von einem ausgewählten Element in einer Listbox zu erhalten. Unter bestimmten Umständen ist das Listenfeld möglicherweise an ein Wörterbuch gebunden, das ist jedoch zur Kompilierzeit nicht bekannt.

Ich möchte etwas ähnliches wie dies tun:

if (listBox.ItemsSource is Dictionary<??>) 
{ 
    KeyValuePair<??> pair = (KeyValuePair<??>)listBox.SelectedItem; 
    object value = pair.Value; 
} 

Gibt es eine Möglichkeit, dies zur Laufzeit mit Reflexion dynamisch zu tun? Ich weiß, dass es möglich ist, Reflektionen mit generischen Typen zu verwenden und die Schlüssel/Wert-Parameter zu bestimmen, aber ich bin mir nicht sicher, ob es eine Möglichkeit gibt, den Rest zu machen, nachdem diese Werte abgerufen wurden.

Antwort

10

Es sollte so etwas wie folgt sein. Ich habe dies in die Antwortbox geschrieben, so dass die Syntax möglicherweise nicht genau stimmt, aber ich habe es in Wiki editierbar gemacht, damit jeder etwas reparieren kann.

if (listBox.ItemsSource.IsGenericType && 
    typeof(IDictionary<,>).IsAssignableFrom(listBox.ItemsSource.GetGenericTypeDefinition())) 
{ 
    var method = typeof(KeyValuePair<,>).GetProperty("Value").GetGetMethod(); 
    var item = method.Invoke(listBox.SelectedItem, null); 
} 
+0

es würde wahrscheinlich besser mit dem Boxed-Wert als mit Reflektion arbeiten. –

+0

Ich bin mir nicht sicher, was du meinst? Sie können nicht einfach eine KeyValuePair boxen, um den Wert daraus zu extrahieren. –

+0

Ihre Lösung hat funktioniert. Ich habe die if-Anweisung geändert, um weiterzumachen und nur "is IDictionary" zu testen (der Typ Ihres Teils funktionierte aus irgendeinem Grund nicht). Ich änderte auch "typeof (KeyValuePair <,>)" zu "listBox.SelectedItem" –

13

Überprüfen Sie, ob es IDictionary implementiert.

Siehe die Definition von System.Collections.IDictionary, um zu sehen, was Ihnen das gibt.

if (listBox.ItemsSource is IDictionary) 
{ 
    DictionaryEntry pair = (DictionaryEntry)listBox.SelectedItem; 
    object value = pair.Value; 
} 

EDIT: Alternative, als ich erkannte KeyValuePair ist zu Dictionary nicht gießbar sind

if (listBox.DataSource is IDictionary) 
{ 
    listBox.ValueMember = "Value"; 
    object value = listBox.SelectedValue; 
    listBox.ValueMember = ""; //If you need it to generally be empty. 
} 

Diese Lösung Reflexion verwendet, aber in diesem Fall müssen Sie die Grunzen Arbeit nicht tun, ListBox macht es für Sie. Auch wenn Sie in der Regel Wörterbücher als Datenquellen haben, können Sie möglicherweise verhindern, dass ValueMember die ganze Zeit zurückgesetzt wird.

+3

Äh, wissen Sie IDictionary hat die IDictionary-Schnittstelle nicht tatsächlich umsetzen ? Dies funktioniert nicht für generische Wörterbücher. Http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx –

+0

Auch wenn es ein Dictionary war , die IDictionary implementiert, dann implementiert es IEnumerable > so würde ich erwarten Fall zu DictionaryEntry zu fehlschlagen. –

+0

Natürlich meinte ich "Cast to DictionaryEntry" oben. –

0

Sie könnten etwas generischer sein und stattdessen fragen, ob es IDictionary implementiert. Dann wird die KeyValue-Kollektion contina plain Objects.

+1

Seien Sie vorsichtig mit Ihrer Terminologie und beziehen Sie sich auf die nicht-generischen Versionen, da Generic wahrscheinlich verwirrend ist (ich weiß, dass ich mich immer selbst korrigieren muss: P) – Guvante

0

Ich glaube eine Warnung ist am Platz.

Wenn Sie testen, ob ein Objekt "etwas" ist, implementieren Sie (teilweise) das Typsystem. Auf das erste "ist ein" folgt oft schnell ein zweites, und bald ist Ihr Code voll von Typ-Checks, die vom Typsystem - zumindest in einem objektorientierten Design - sehr gut gehandhabt werden sollten.

Natürlich weiß ich nichts über den Kontext der Frage. Ich weiß, eine 2000 Linie Datei in unserer eigenen Code-Basis, die String Konvertierungen 50 verschiedene Objekt-Handles ... :(

0
if(typeof(IDictionary).IsAssignableFrom(listBox.ItemsSource.GetType())) 
{ 

} 
3

Ich weiß, diese Frage vor vielen Jahren gefragt wurde, aber es ist öffentlich noch sichtbar.

Es gab hier einige Beispiele in diesem Thema vorgeschlagen und in dieser:
Determine if type is dictionary [duplicate]

aber es gibt nur wenige Mismatches, so dass ich möchte, dass meine Lösung teilen

Kurze Antwort:

var dictionaryInterfaces = new[] 
{ 
    typeof(IDictionary<,>), 
    typeof(IDictionary), 
    typeof(IReadOnlyDictionary<,>), 
}; 

var dictionaries = collectionOfAnyTypeObjects 
    .Where(d => d.GetType().GetInterfaces() 
     .Any(t=> dictionaryInterfaces 
      .Any(i=> i == t || t.IsGenericType && i == t.GetGenericTypeDefinition()))) 

Längere Antwort:
Ich glaube, dies ist der Grund, warum Menschen machen Fehler:

//notice the difference between IDictionary (interface) and Dictionary (class) 
typeof(IDictionary<,>).IsAssignableFrom(typeof(IDictionary<,>)) // true 
typeof(IDictionary<int, int>).IsAssignableFrom(typeof(IDictionary<int, int>)); // true 

typeof(IDictionary<int, int>).IsAssignableFrom(typeof(Dictionary<int, int>)); // true 
typeof(IDictionary<,>).IsAssignableFrom(typeof(Dictionary<,>)); // false!! in contrast with above line this is little bit unintuitive 

so lassen sagen, dass wir diese Art haben:

public class CustomReadOnlyDictionary : IReadOnlyDictionary<string, MyClass> 
public class CustomGenericDictionary : IDictionary<string, MyClass> 
public class CustomDictionary : IDictionary 

und diese Instanzen:

var dictionaries = new object[] 
{ 
    new Dictionary<string, MyClass>(), 
    new ReadOnlyDictionary<string, MyClass>(new Dictionary<string, MyClass>()), 
    new CustomReadOnlyDictionary(), 
    new CustomDictionary(), 
    new CustomGenericDictionary() 
}; 

also, wenn wir verwenden .IsAssignableFrom() Methode:

var dictionaries2 = dictionaries.Where(d => 
    { 
     var type = d.GetType(); 
     return type.IsGenericType && typeof(IDictionary<,>).IsAssignableFrom(type.GetGenericTypeDefinition()); 
    }); // count == 0!! 

wir jede Instanz nicht bekommen

so beste Weg ist, alle Schnittstellen zu bekommen und überprüfen, ob einer von ihnen Wörterbuch-Schnittstelle ist:

var dictionaryInterfaces = new[] 
{ 
    typeof(IDictionary<,>), 
    typeof(IDictionary), 
    typeof(IReadOnlyDictionary<,>), 
}; 

var dictionaries2 = dictionaries 
    .Where(d => d.GetType().GetInterfaces() 
     .Any(t=> dictionaryInterfaces 
      .Any(i=> i == t || t.IsGenericType && i == t.GetGenericTypeDefinition()))) // count == 5