2009-12-04 17 views
5

Qualcuno ha sentito parlare di un "dizionario di tipo" che utilizza i tipi come chiavi e supporta l'ereditarietà?Tipo dizionario?

Nella mia domanda mi piacerebbe avere un dizionario da tipi di funzioni, un po 'come questo:

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

L'idea è che sarebbe stato utilizzato per trasformare un oggetto in qualche modo in base alla sua tipo:

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

Un dizionario comune ha lo svantaggio che il tipo deve corrispondere esattamente. Quindi, se ho scritto un trasformatore per IList < T>, è inutile metterlo nel dizionario Transformers perché nessun oggetto ha il tipo IList < T> (solo T [], Lista < T>, etc.) In altre parole, , se obj è una lista < T>, il trasformatore per IList < T> non verrà trovato da una ricerca in un dizionario ordinario.

Supponendo che non ci sia qualcosa come un TypeDictionary < TValue, potrei considerare di scriverne uno se non è troppo difficile. Qualche idea su come potrebbe essere realizzata?

risposta

2

Dovresti essere in grado di utilizzare un dizionario con un custom comparer che utilizza Type.IsAssignableFrom per confrontare le chiavi.

Aggiornamento: Come sottolineato da Qwertie, questo non funziona perché non è possibile implementare un calcolo ripetibile del codice hash basato su un tipo, le sue interfacce e le classi antenate. His answer fornisce una possibile soluzione ripetutamente facendo tabella hash look up per il tipo, interfacce e classi antenati fino a quando non trova una corrispondenza.

L'unico problema di questa soluzione è che non si dispone di alcun modo per specificare che corrispondono a prendere quando ci sono più corrispondenze. Se hai bisogno di tale flessibilità e controllo, ti suggerisco di considerare il modello di progettazione chain-of-responsibility. Ogni trasformatore può essere un collegamento nella catena ed è responsabile per determinare se può essere applicato all'oggetto. In caso contrario, passa la richiesta al collegamento successivo. L'ordine dei trasformatori nella catena determina la priorità. Perdi la velocità di un hash table, ma stavi perdendo un po 'di quella velocità comunque a causa di più look up.

+1

Che non avrebbe funzionato. Quale codice hash restituirebbe IEqualityComparer per una classe B che deriva da A e implementa IA e IB? Inoltre, tieni presente che il dizionario dovrebbe essere in grado di contenere le chiavi per 'Lista ', 'IList ' e 'oggetto' contemporaneamente. – Qwertie

+0

Hai ragione, non ci ho pensato. –

+0

@Qwertie in tal caso, cosa restituirebbe il dizionario se nel dizionario fossero presenti più corrispondenze per un tipo? Dovrebbe restituire tutte le occorrenze, solo le più specializzate, ecc.? –

1

E viene in mente che il setter dizionario non ha una semantica diversa da un dizionario ordinario, così un approccio è quello di utilizzare un dizionario standard con la ricerca specialistica:

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

Si noti che se un deriva di classe B dalla classe A e dalle interfacce IA e IB, e vi è un valore assegnato a ciascuno di questi tipi, è ambiguo: deve essere restituito il valore per A, IA o IB? L'implementazione sopra sceglie la prima interfaccia che trova, e solo se non vengono trovate interfacce, cerca la classe base.

Non ho idea di quanto sia buona la prestazione di questo dizionario. Se GetInterfaces() o la proprietà BaseType è lenta, renderà le prestazioni di ricerca piuttosto scadenti (ogni volta che il tipo esatto richiesto non è nel dizionario).

Problemi correlati