2009-03-23 15 views
6

¿Alguien me puede explicar 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 admite List<IPackable>, pasando una lista de List<OrderItem> no funciona?.NET Casting Generic List

¿Alguien sabe cómo puedo lograr esta funcionalidad?

Código:

public interface IPackable { 
     double Weight{ get; } 
} 

public class OrderItem : IPackable 


public List<IShipMethod> GetForShipWeight(List<IPackable> packages) { 
    double totalWeight = 0; 
    foreach (IPackable package in packages) { 
     totalWeight += package.Weight; 
    } 
} 

El siguiente código no funciona.

List<OrderItem> orderItems = new List<OrderItem>(); 
List<IShipMethod> shipMethods = GetForShipWeight(orderItems); 
+0

Por favor enviar el código relevante y lo que os perturban específica tener (error de compilación, error de tiempo de ejecución, etc.) – Misko

Respuesta

7

La respuesta de JMD es correcta. Para solucionar este problema, puede intentar esto:

List<IPackable> orderItems = new List<IPackable>(); 
List<IShipMethod> shipMethods = GetForShipWeight(orderItems); 

O, si la lista debe estar fuertemente tipado como artículos de pedido, entonces este (3.0 solamente, lo siento):

List<IShipMethod> shipMethods = 
    GetForShipWeight(orderItems.Cast<IPackable>().ToList()); 
14

JMD es la mitad correcta. 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<B> es una subclase de List<A>.

Y he aquí por qué.

List<A> expone algunos métodos de covarianzas (devuelve un valor) y algunos métodos de contravarianzas (acepta un valor como parámetro).

p. Ej.

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

Si List<B> hereda de List<A> ... de lo que sería capaz de hacer List<B>.Add(A);

Por lo tanto, ya que se perdería todo tipo de seguridad genéricos.

1

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

public interface IPackable { double Weight { get; } } 
public interface IShipMethod { } 

public class OrderItem : IPackable { } 

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

una solución alternativa que también trabaja para .NET 3,5

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