2011-02-18 13 views
17

Quiero tener un diccionario que asigne cadenas a listas genéricas de distintos tipos. es decir, en la forma siguiente:Diccionario de listas genéricas o tipos variables

 
Key  Value 
string  List<T> 
string  List<U> 
string  List<V> 
string  List<U> 
... 

Actualmente estoy usando un Dictionary<string, IList> y después se extrajo la lista establecimiento inflexible de cada diccionario KeyValuePair<string, IList> pair la entrada de la siguiente manera:

Type layerType = pair.Value.GetType().GetGenericArguments()[0]; 
List<layerType> objectsClicked = pair.Value as List<layerType>; 

¿Existe una manera más agradable de hacer esto ?

[Editar] Como se ha señalado, lo anterior no se compila, disculpas, eso es lo que obtienes cuando haces una pregunta mientras aún trabajas en algunas cosas. Algo más de explicación. Estoy haciendo un visor de datos espaciales básicos. La vista final consiste en un grupo de Layer<T> s. Cada capa proporciona un delegado para representar su tipo (dado un desplazamiento y una escala) y una forma de verificar cuáles de sus objetos están en la ventana actual. Para las pruebas de impacto, me gustaría una lista para cada capa de los objetos que han sido golpeados. Esa lista sería List<Point> para una capa Point, etc ... La agrupación de los hits de todos los Layer<T> s sería una colección de listas fuertemente tipadas.

+2

El código de ejemplo proporcionado no se compilará. En cualquier caso, sería de gran ayuda si pudieras decirnos a) qué vas a hacer con la lista una vez que la saques b) cuál es el problema más grande que estás tratando de resolver. – Ani

+1

Lo que tienes no compilará. No puede pasar un tipo de objeto como un parámetro de tipo genérico. ¿Por qué incluso necesitas genéricos si no estás accediendo a la lista de manera fuertemente tipada? – Josh

+1

Puesto que coloca estas listas en el mismo diccionario, debe haber algunos motivos comunes entre ellas (por ejemplo, tienen la misma clase/interfaz base o algo así). Debe proporcionar más información. –

Respuesta

35

¿Qué tal Dictionary<string, dynamic> asumiendo que usted está en C# 4

Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>(); 
Dict.Add("int", new List<int>()); 
Dict.Add("string", new List<string>()); 

Dict["int"].Add(12); 
Dict["string"].Add("str"); 

foreach (KeyValuePair<string, dynamic> pair in Dict) { 
    Type T = pair.Value.GetType(); 
    Console.WriteLine(T.GetGenericArguments()[0].ToString()); 
} 

que imprime

System.Int32

System.String

es eso lo que '¿que estas buscando?

+4

Creo que su Dictionary es mucho mejor. No lo confundas con dinámico. – Euphoric

+0

¿Por qué el voto a favor? Esto parece hacer exactamente lo que está buscando. –

+0

Podría haber hecho lo mismo con un nuevo Diccionario () sin usar la dinámica – xanatos

2

El uso de Dictionary<string, IList> es posiblemente la única solución. Pero su código es incorrecto, no puede usar genéricos como ese. No puedes crear tipo dinámicamente así.

El problema general con su necesidad es que no es compatible con lenguaje fuerte como C#. En un lenguaje fuerte, debe saber qué tipo es EXACTAMENTE. Pero esto no puede hacerse usando medios normales. También su comprensión de los genéricos es incorrecta. Es la única extensión en tiempo de compilación del tipo.

Y la idea general: En su caso, usando algún tipo de jerarquía OOP de tipos que guarde en esas listas. Esta será una idea mucho mejor y más segura y no hará que todos los que miren su código se rasguen el pelo.

+2

Situaciones como esta en las que necesita flexibilidad con el sistema de tipos son * exactamente * para lo que se diseñó la dinámica (entre otras cosas, como una reflexión más fácil). –

2

Voy a tomar un término medio entre Euphoric y Adam, debe hacer uso de ambos IList y dynamic. Esto es lo que creo que es más correcto:

var dict = new Dictionary<string, IList>(); 
dict.Add("u", new List<U>()); 
dict.Add("v", new List<V>()); 

// in case of members you know they exist on an IList 
dict["u"].Add(new U()); 
dict["v"].Add(new V()); 

// in case you know what you are going to get back, in which case you should cast 
var uProperty = (dict["u"][0] as U).UProperty 
var vProperty = (dict["v"][0] as V).VProperty 

// in case your're not sure of  
(dict[someKey] as dynamic)[someIndex].SomeMember...; 

Todos estos son mucho más simples de depender de la reflexión. La idea básica es declarar el tipo de valor del diccionario como IList para aclarar sus intenciones desde el principio, mientras usa dynamic para facilitar la monstruosidad de la reflexión y reducir el código.

0

De hecho, creo el enfoque más limpio es crear un contenedor para su diccionario:

public class GlobalStore 
{ 
    private readonly IDictionary<Type, IEnumerable> _globalStore; 

    public GlobalStore() 
    { 
     _globalStore = new ConcurrentDictionary<Type, IEnumerable>(); 
    } 

    public IEnumerable<T> GetFromCache<T>() 
     where T : class 
    { 
     return (IEnumerable<T>) _globalStore[typeof(T)]; 
    } 

    public void SetCache<T>(IEnumerable<T> cache) 
     where T : class 
    { 
     _globalStore[typeof(T)] = cache; 
    } 
} 

Aquí está una prueba para él:

[TestClass] 
public class GlobalStoreTest 
{ 
    [TestMethod] 
    public void GlobalStore_Test() 
    { 
     //Arrange 
     var globalStore = new GlobalStore(); 
     globalStore.SetCache(new List<ClientModel> 
     { 
      new ClientModel 
      { 
       ClientId = 1, 
       ClientName = "Client1" 
      }, 
      new ClientModel 
      { 
       ClientId = 2, 
       ClientName = "Client2" 
      } 
     }); 

     //Act 
     var clients = globalStore.GetFromCache<ClientModel>(); 

     //Assert 
     Assert.AreEqual(2, clients.Count()); 
    } 
} 
Cuestiones relacionadas