2009-12-04 3 views
5

Hat jemand von einem "Typ-Wörterbuch" gehört, das Typen als Schlüssel verwendet und Vererbung unterstützt?Typ Wörterbuch?

In meiner Anwendung würde Ich mag ein Wörterbuch von Typen Funktionen haben, irgendwie wie folgt aus:

Dictionary<Type, Func<object, object>> Transformers; 

Die Idee ist, dass es verwendet werden würde, um ein Objekt in irgendeiner Art und Weise zu verändern, basierend auf seiner Typ:

// Transform an object 'obj' 
object result = Transformers[obj.GetType()](obj) 

Ein gewöhnliches Wörterbuch hat den Nachteil, dass der Typ genau übereinstimmen muss. Wenn ich also einen Transformator für IList < T> geschrieben habe, ist es sinnlos, ihn in das Transformers-Dictionary zu schreiben, weil kein Objekt vom Typ IList < T> ist (nur T [], Liste < T>, usw.) Mit anderen Worten , wenn obj ist eine Liste < T>, der Transformator für IList < T> wird nicht durch eine Suche in einem gewöhnlichen Wörterbuch gefunden werden.

Angenommen, es gibt kein TypeDictionary < TValue>, könnte ich einen schreiben, wenn es nicht zu schwer ist. Irgendwelche Ideen, wie es erreicht werden könnte?

Antwort

2

Sie sollten in der Lage sein, ein Wörterbuch mit einer custom comparer zu verwenden, die Type.IsAssignableFrom verwendet, um die Schlüssel zu vergleichen.

Aktualisierung: Wie Qwertie darauf hingewiesen hat, funktioniert dies nicht, da Sie keine wiederholbare Hashcodeberechnung basierend auf einem Typ, seinen Schnittstellen und Vorgängerklassen implementieren können. His answer bietet eine mögliche Lösung, indem wiederholt Hashtabellen-Lookups für den Typ, die Schnittstellen und die Vorgängerklassen durchgeführt werden, bis eine Übereinstimmung gefunden wird.

Das einzige Problem mit dieser Lösung ist, dass Sie keine Möglichkeit haben anzugeben, welche Übereinstimmung bei mehreren Übereinstimmungen zu treffen ist. Wenn Sie diese Flexibilität und Kontrolle benötigen, schlage ich vor, dass Sie das Designmuster chain-of-responsibility berücksichtigen. Jeder Transformator könnte ein Glied in der Kette sein, und er ist dafür verantwortlich zu bestimmen, ob er auf das Objekt angewendet werden kann. Wenn nicht, übergibt es die Anfrage an den nächsten Link. Die Reihenfolge der Transformatoren in der Kette bestimmt die Priorität. Sie verlieren zwar die Geschwindigkeit einer Hashtabelle, aber Sie haben ohnehin aufgrund von Mehrfach-Lookups einen Teil dieser Geschwindigkeit verloren. Wenn eine Klasse B herleitet

public class TypeDictionary<TValue> : Dictionary<Type, TValue> 
{ 
    public new TValue this[Type key] 
    { 
     get { 
      TValue value; 
      if (TryGetValue(key, out value)) 
       return value; 
      throw new KeyNotFoundException("Not found: " + key.Name); 
     } 
    } 
    public new bool TryGetValue(Type key, out TValue value) 
    { 
     if (base.TryGetValue(key, out value)) 
      return true; 

     Type[] interfaces = key.GetInterfaces(); 
     for (int i = 0; i < interfaces.Length; i++) 
      if (base.TryGetValue(interfaces[i], out value)) 
       return true; 

     Type @base = key.BaseType; 
     if (@base != null && TryGetValue(@base, out value)) 
      return true; 

     return false; 
    } 
} 

Beachten Sie, dass:

+1

Das würde nicht funktionieren. Welchen Hashcode würde der IEqualityComparer für eine von A abgeleitete Klasse B zurückgeben und IA und IB implementieren? Beachten Sie auch, dass das Dictionary Schlüssel gleichzeitig für die Listen ',' IList 'und' object' enthalten kann. – Qwertie

+0

Sie haben Recht, ich habe das nicht durch gedacht. –

+0

@Qwertie in diesem Fall, was würde Ihr Wörterbuch zurückgeben, wenn es mehrere Übereinstimmungen im Wörterbuch für einen Typ gäbe? Sollte es alle Vorkommen zurückgeben, nur die am meisten spezialisierten, usw.? –

1

Ihm fällt mir, dass das Wörterbuch Setter nicht andere Semantik von einem normalen Wörterbuch hat, so ein Ansatz ist, einen Standard-Wörterbuch mit spezialisierter Suche verwendet werden von der Klasse A und den Schnittstellen IA und IB, und jedem dieser Typen ist ein Wert zugeordnet, der mehrdeutig ist: Soll der Wert für A, IA oder IB zurückgegeben werden? Die obige Implementierung wählt die erste gefundene Schnittstelle aus, und nur wenn keine Schnittstellen gefunden werden, sucht sie nach der Basisklasse.

Ich habe keine Ahnung, wie gut die Leistung dieses Wörterbuch ist. Wenn GetInterfaces() oder die BaseType-Eigenschaft langsam ist, wird die Lookup-Leistung ziemlich schlecht (wenn der genaue Typ, den Sie anfordern, nicht im Wörterbuch enthalten ist).

Verwandte Themen