IDictionary en .NET 4 no covariante

IDictionary en .NET 4 / Silverlight 4 no es compatible con la covarianza, es decir, no puedo hacer una

 IDictionary myDict = new Dictionary(); 

análogo a lo que puedo hacer con IEnumerable s ahora.

Probablemente se reduce a KeyValuePair tampoco es covariante. Creo que la covarianza debe permitirse en los diccionarios, al menos para los valores.

Entonces, ¿es eso un error o una característica? ¿Alguna vez vendrá, tal vez en .NET 37.4?

ACTUALIZACIÓN (2 años después):

Habrá un IReadOnlyDictionary en .NET 4.5, pero no será covariante tampoco :·/ , porque deriva de IEnumerable<KeyValuePair> , y KeyValuePair no es una interfaz y por lo tanto no puede ser covariante.

El equipo de BCL debería rediseñar mucho para poder utilizar ICovariantPair . Tampoco son posibles los indexadores fuertemente tipados a la this[TKey key] para las interfaces covariantes. Un fin similar solo se puede lograr colocando un método de extensión GetValue(this IReadOnlyDictionary self, TKey key) algún lugar que de alguna manera internamente tendría que llamar a una implementación real, lo que podría parecer un enfoque bastante desordenado.

Es una característica. .NET 4.0 solo admite una covarianza segura . El reparto que mencionas es potencialmente peligroso, ya que podrías agregar un elemento que no sea de cuerda al diccionario si fuera posible:

 IDictionary myDict = new Dictionary(); myDict["hello"] = 5; // not an string 

Por otro lado, IEnumerable es una interfaz de solo lectura. El parámetro de tipo T está solo en sus posiciones de salida (tipo de retorno de la propiedad Current ) por lo que es seguro tratar IEnumerable como IEnumerable .

Pero entonces podrías decir

 myDict.Add("Hello, world!", new DateTime(2010, 1, 27)); 

que fallaría miserablemente El problema es que TValue en IDictionary se usa tanto en las posiciones de entrada como de salida. Esto es:

 myDict.Add(key, value); 

y

 TValue value = myDict[key]; 

Entonces, ¿es eso un error o una característica?

Es por diseño.

¿Alguna vez vendrá, tal vez en .NET 37.4?

No, es intrínsecamente inseguro.

Tuve un problema similar, pero con tipos derivados más especializados (en lugar de objetos de los que todo se deriva)

El truco es hacer que el método sea genérico y poner una cláusula where poniendo la restricción relevante. Suponiendo que se trata de tipos básicos y tipos derivados, lo siguiente funciona:

 using System; using System.Collections.Generic; namespace GenericsTest { class Program { static void Main(string[] args) { Program p = new Program(); p.Run(); } private void Run() { Dictionary a = new Dictionary { { 1, new SpecialType1 { BaseData = "hello", Special1 = 1 } }, { 2, new SpecialType1 { BaseData = "goodbye", Special1 = 2 } } }; Test(a); } void Test(Dictionary data) where Y : BaseType { foreach (BaseType x in data.Values) { Console.Out.WriteLine(x.BaseData); } } } public class BaseType { public string BaseData { get; set; } } public class SpecialType1 : BaseType { public int Special1 { get; set; } } } 

.NET 4 solo admite la covarianza no en . Funciona con IEnumerable porque IEnumerable es de solo lectura.

Una IDictionary para un tipo específico de covarianza útil en IDictionary

 public static class DictionaryExtensions { public static IReadOnlyDictionary> ToReadOnlyDictionary( this IDictionary> toWrap) { var intermediate = toWrap.ToDictionary(a => a.Key, a => a.Value!=null ? a.Value.ToArray().AsEnumerable() : null); var wrapper = new ReadOnlyDictionary>(intermediate); return wrapper; } }