.NET Casting Generic List

¿Puede alguien explicarme por qué en .NET 2.0 si tengo una interfaz, IPackable y una clase que implementa esa interfaz OrderItem , cuando tengo un método que toma una List , que pasa en una lista de List hace ¿no trabajo?

¿Alguien sabe cómo podría lograr esta funcionalidad?

Código:

 public interface IPackable { double Weight{ get; } } public class OrderItem : IPackable public List GetForShipWeight(List packages) { double totalWeight = 0; foreach (IPackable package in packages) { totalWeight += package.Weight; } } 

El siguiente código no funciona.

 List orderItems = new List(); List shipMethods = GetForShipWeight(orderItems); 

La característica se llama covarianza / contravarianza y será compatible con c # 4.0. Puede leer sobre esto aquí: http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

JMD es mitad correcto. De hecho, es absolutamente incorrecto decir que podremos lanzar una lista genérica con C # 4.0. Es cierto que la covarianza y la contravariancia se admitirán en C # 4.0, pero solo funcionará con la interfaz y el delegado, y habrá muchas restricciones. Por lo tanto, no funcionará con List .

La razón es realmente simple.

Si B es una subclase de A, no podemos decir que List es una subclase de List .

Y aquí está el por qué.

List expone algunos métodos de covarianzas (que devuelven un valor) y algunos métodos de contravarianzas (que aceptan un valor como parámetro).

p.ej

  • List expone Add(A);
  • List expone Add(B);

Si List hereda de List … de lo que podría hacer List.Add(A);

Por lo tanto, perdería todo tipo de seguridad de los generics.

La respuesta de JMD es correcta. Para una solución, puede intentar esto:

 List orderItems = new List(); List shipMethods = GetForShipWeight(orderItems); 

O bien, si la lista debe ser fuertemente tipificada como artículos de pedido, entonces esto (solo 3.0, lo siento):

 List shipMethods = GetForShipWeight(orderItems.Cast().ToList()); 

Una solución alternativa que también funciona para .NET 3.5

 List shipMethods = GetForShipWeight(orderItems).ConvertAll(sm => sm as IShipMethod); 

En realidad, puedes resolver esto haciendo de GetForShipWeight una función genérica:

 public interface IPackable { double Weight { get; } } public interface IShipMethod { } public class OrderItem : IPackable { } public List GetForShipWeight(List packages) where T : IPackable { List ship = new List(); foreach (IPackable package in packages) { // Do something with packages to determine list of shipping methods } return ship; } public void Test() { List orderItems = new List(); // Now compiles... List shipMethods = GetForShipWeight(orderItems); }