varianza variacion propiedades poblacional paso para muestral estandar ejercicios ejemplos ejemplo desviacion datos coeficiente agrupados c# covariance

c# - variacion - varianza para datos agrupados



Problema de varianza de C#: Asignar Lista<Derivado> como Lista<Base> (4)

Mire el siguiente ejemplo (parcialmente tomado de MSDN Blog ):

class Animal { } class Giraffe : Animal { } static void Main(string[] args) { // Array assignment works, but... Animal[] animals = new Giraffe[10]; // implicit... List<Animal> animalsList = new List<Giraffe>(); // ...and explicit casting fails List<Animal> animalsList2 = (List<Animal>) new List<Giraffe>(); }

¿Es esto un problema de covarianza? ¿Esto se admitirá en la futura versión de C # y existen algunas soluciones inteligentes (utilizando únicamente .NET 2.0)?


Bueno, esto ciertamente no será compatible con C # 4. Hay un problema fundamental:

List<Giraffe> giraffes = new List<Giraffe>(); giraffes.Add(new Giraffe()); List<Animal> animals = giraffes; animals.Add(new Lion()); // Aargh!

Mantenga las jirafas seguras: simplemente diga no a la varianza insegura.

La versión de matriz funciona porque las matrices admiten varianza de tipo de referencia, con comprobación de tiempo de ejecución. El objetivo de los genéricos es proporcionar seguridad de tipo de tiempo de compilación .

En C # 4 habrá soporte para la varianza genérica segura , pero solo para interfaces y delegados. Entonces podrás hacer:

Func<string> stringFactory = () => "always return this string"; Func<object> objectFactory = stringFactory; // Safe, allowed in C# 4

Func<out T> es covariante en T porque T solo se usa en una posición de salida. Compare eso con Action<in T> que es contravariante en T porque T solo se usa en una posición de entrada allí, lo que lo hace seguro:

Action<object> objectAction = x => Console.WriteLine(x.GetHashCode()); Action<string> stringAction = objectAction; // Safe, allowed in C# 4

IEnumerable<out T> es covariante, haciendo esto correcto en C # 4, como lo señalaron otros:

IEnumerable<Animal> animals = new List<Giraffe>(); // Can''t add a Lion to animals, as `IEnumerable<out T>` is a read-only interface.

En términos de trabajar alrededor de esto en su situación en C # 2, ¿necesita mantener una lista o le gustaría crear una nueva lista? Si eso es aceptable, List<T>.ConvertAll es tu amigo.


En términos de List<T> , me temo que no tienes suerte. Sin embargo, .NET 4.0 / C # 4.0 agrega soporte para interfaces covariantes / contravariantes. Específicamente, IEnumerable<T> ahora se define como IEnumerable<out T> , lo que significa que el parámetro de tipo ahora es covariante .

Esto significa que puedes hacer algo como esto en C # 4.0 ...

// implicit casting IEnumerable<Animal> animalsList = new List<Giraffe>(); // explicit casting IEnumerable<Animal> animalsList2 = (IEnumerable<Animal>) new List<Giraffe>();

Nota: los tipos de matriz también han sido covariantes (al menos desde .NET 1.1).

Creo que es una lástima que el soporte de varianza no se haya agregado para IList<T> y otras interfaces genéricas similares (o incluso para clases genéricas), pero bueno, al menos tenemos algo.


Funcionará en C # 4 para IEnumerable<T> , por lo que puede hacer:

IEnumerable<Animal> animals = new List<Giraffe>();

Sin embargo, List<T> no es una proyección covariante, por lo que no puede asignar listas como lo hizo anteriormente ya que podría hacer esto:

List<Animal> animals = new List<Giraffe>(); animals.Add(new Monkey());

Lo cual claramente no es válido.


La covarianza / contravariancia no puede ser soportada en colecciones mutables como otros han mencionado porque es imposible garantizar la seguridad del tipo en ambos sentidos en el momento de la compilación; sin embargo, es posible hacer una conversión rápida de ida en C # 3.5, si eso es lo que está buscando:

List<Giraffe> giraffes = new List<Giraffe>(); List<Animal> animals = giraffes.Cast<Animal>().ToList();

Por supuesto, no es lo mismo, en realidad no es una covarianza; en realidad estás creando otra lista, pero es una "solución alternativa", por así decirlo.

En .NET 2.0, puede aprovechar la covarianza de matriz para simplificar el código:

List<Giraffe> giraffes = new List<Giraffe>(); List<Animal> animals = new List<Animal>(giraffes.ToArray());

Pero ten en cuenta que en realidad estás creando dos nuevas colecciones aquí.