valor obtener new ejemplos diccionario collection c# generics dictionary casting covariance

obtener - new dictionary c#



¿Por qué no puedo convertir un diccionario de un tipo de valor en diccionario de otro tipo de valor cuando los tipos de valores se pueden convertir entre sí? (3)

Piensa en lo que sucedería si se permitiera y luego lo hiciste:

getFromDict.Add(34, new HashSet<string>);

Eso está perfectamente permitido; HashSet<string> implementa IEnumerable<string> y se puede agregar como un valor a un Dictionary<int, IEnumerable<string>> . No obstante, no se puede agregar a un Dictionary<int, List<string>> , que es lo que realmente es ese objeto.

Si desea utilizarlo como IDictionary<int, IEnumerable<string>> solo IDictionary<int, IEnumerable<string>> puede obtener una buena eficacia de una clase contenedora que IEnumerable<string> a IEnumerable<string> como va.

De lo contrario, debe copiar los valores en un nuevo Dictionary<int, IEnumerable<string>> .

Posible duplicado:
En C #, ¿por qué no se puede almacenar un objeto List <string> en una variable List <object>?

¿Por qué el siguiente trabajo no funciona?

List<string> castMe = new List<string>(); IEnumerable<string> getFromCast = (IEnumerable<string>)castMe; // allowed. Dictionary<int, List<string>> castMeDict = new Dictionary<int, List<string>>(); Dictionary<int, IEnumerable<string>> getFromDict = (Dictionary<int, IEnumerable<string>>)castMeDict; // Not allowed

¿Es esto una falla en el mecanismo de conversión del Dictionary , o en mi opinión que esto debería permitirse?

Gracias.


¿Es esto una falla en el mecanismo de conversión del diccionario, o en mi opinión que esto debería permitirse?

En tu forma de pensar Está esperando que los diccionarios sean covariantes en sus conversiones. No lo son, por la siguiente razón. Supongamos que lo fueran, y deducir qué podría salir mal:

Dictionary<int, List<string>> castMeDict = new Dictionary<int, List<string>>(); Dictionary<int, IEnumerable<string>> getFromDict = (Dictionary<int, IEnumerable<string>>)castMeDict; castMeDict[123] = new List<string>(); IEnumerable<string> strings = getFromDict[123]; // No problem! getFromDict[123] = new string[] { "hello" }; // Big problem!

Una matriz de cadena es convertible a IEnumerable<string> pero no a List<string> . Simplemente coloca algo que no es una lista de cadenas en un diccionario que solo puede tomar una lista de cadenas.

En C # los tipos genéricos pueden ser covariantes o contravariantes si se cumplen todas las condiciones siguientes:

  • Estás usando C # 4 o mejor.
  • El tipo genérico variable es una interfaz o delegado.
  • La varianza es demostrablemente segura. (La especificación C # describe las reglas que usamos para determinar la seguridad de la varianza. El archivo de documentación de la versión C # 4.0 se puede descargar [aquí] . Consulte la sección 23.5).
  • Los argumentos de tipo que varían son todos los tipos de referencia.
  • El tipo ha sido marcado específicamente como seguro para la varianza.

La mayoría de esas condiciones no se cumplen para el diccionario; no es una interfaz o un delegado, no es seguro y el tipo no está marcado como seguro para la varianza. Entonces, no hay variación para los diccionarios.

IEnumerable<T> por el contrario cumple con todas esas condiciones. Puede convertir IEnumerable<string> a IEnumerable<object> en C # 4.

Si el tema de la varianza le interesa, considere leer mis dos docenas de artículos sobre el tema:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/


Investigue la contravariancia y la covarianza. Para un ejemplo particular de por qué un caso así podría ser malo, consulte esta respuesta de Jon Skeet .