2009-12-04 13 views
5

¿Alguien ha oído hablar de un "diccionario de tipo" que utiliza tipos como claves y admite la herencia?Tipo Diccionario?

En mi solicitud me gustaría tener un diccionario de tipos de funciones, más o menos así:

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

La idea es que se utiliza para transformar un objeto de alguna manera en función de su tipo:

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

Un diccionario ordinaria tiene la desventaja de que el tipo debe coincidir exactamente. Entonces, si escribí un transformador para IList < T>, no tiene sentido ponerlo en el diccionario de Transformers porque ningún objeto tiene el tipo IList < T> (solo T [], List < T>, etc.) En otras palabras , si obj es una lista < T>, el transformador para IList < T> no se encontrará mediante una búsqueda en un diccionario común.

Suponiendo que no existe una TypeDictionary < TValue>, podría considerar escribir una si no es demasiado difícil. ¿Alguna idea de cómo se podría lograr?

Respuesta

2

Usted debe ser capaz de usar un diccionario con un custom comparer que utiliza Type.IsAssignableFrom comparar las llaves.

Actualización: Como Qwertie señaló, esto no funciona porque no se puede poner en práctica un cálculo código hash repetible sobre la base de un tipo, sus interfaces y clases ancestros. His answer proporciona una posible solución al hacer repetidamente búsquedas de tablas hash para el tipo, las interfaces y las clases antecesoras hasta que encuentre una coincidencia.

El único problema con esa solución es que no tiene forma de especificar qué partido tomar cuando hay varias coincidencias. Si necesita esa flexibilidad y control, le sugiero que considere el patrón de diseño chain-of-responsibility. Cada transformador podría ser un enlace en la cadena, y es responsable de determinar si se puede aplicar al objeto. Si no, pasa la solicitud al siguiente enlace. El orden de los transformadores en la cadena determina la prioridad. Pierdes la velocidad de una tabla hash, pero de todos modos perdías parte de esa velocidad debido a múltiples búsquedas.

+1

Eso no funcionaría. ¿Qué código hash obtendría el IEqualityComparer para una clase B que deriva de A e implementa IA e IB? Además, tenga en cuenta que el Diccionario debería poder mantener las teclas para 'List ', 'IList ' y 'object' al mismo tiempo. – Qwertie

+0

Tienes razón, no pensé en eso. –

+0

@Qwertie en ese caso, ¿qué devolvería su diccionario si hubiera varias coincidencias en el diccionario para un tipo? ¿Debería devolver todas las ocurrencias, solo las más especializadas, etc.? –

1

Se me ocurre que el diccionario de la moda no tiene una semántica diferente a partir de un diccionario ordinaria, por lo que un enfoque consiste en utilizar un diccionario estándar con las operaciones de búsqueda especializada:

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

Tenga en cuenta que si una clase B se deriva de la clase A y las interfaces IA e IB, y hay un valor asignado a cada uno de esos tipos, es ambiguo: ¿debería devolverse el valor de A, IA o IB? La implementación anterior elige la primera interfaz que encuentra, y solo si no se encuentran interfaces, ¿busca la clase base?

No tengo idea de lo bueno que es el rendimiento de este diccionario. Si GetInterfaces() o la propiedad BaseType es lenta, hará que el rendimiento de búsqueda sea bastante malo (siempre que el tipo exacto que solicite no esté en el diccionario).

Cuestiones relacionadas