2009-03-23 7 views
6

Kann mir jemand erklären, warum in .NET 2.0, wenn ich eine Schnittstelle, IPackable und eine Klasse, die diese Schnittstelle implementiert OrderItem, wenn ich eine Methode habe, die in einer List<IPackable>, übergibt eine Liste von List<OrderItem> funktioniert nicht?.NET Casting Generic Liste

Wer weiß, wie ich diese Funktionalität erreichen könnte?

Code:

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; 
    } 
} 

Der folgende Code funktioniert nicht.

+0

arbeitet Bitte postet den entsprechenden Code und welche spezifischen Probleme Sie haben (Buildfehler, Laufzeitfehler, usw.). – Misko

Antwort

7

JMD Antwort richtig ist. Für dieses Problem zu umgehen, können Sie dies versuchen:

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

Oder, wenn die Liste muss stark als Order eingegeben werden, dann ist diese (3,0 nur, sorry):

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

JMD Hälfte korrekt ist. In der Tat ist es absolut falsch zu sagen, dass wir in der Lage sein werden, eine generische Liste mit C# 4.0 zu erzeugen. Es ist richtig, dass Covarianz und Kontravarianz in C# 4.0 unterstützt werden, aber es wird nur mit Schnittstelle und Delegaten funktionieren und es wird viele Einschränkungen geben. Daher wird es nicht mit List funktionieren.

Der Grund dafür ist ganz einfach. Wenn B eine Unterklasse von A ist, können wir nicht sagen, dass List<B> eine Unterklasse von List<A> ist.

Und hier ist der Grund.

List<A> macht einige Kovarianzmethoden (Rückgabe eines Wertes) und einige Contravarianzmethoden (Annahme eines Wertes als Parameter) verfügbar.

z.B.

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

Wenn List<B> erbt von List<A> aussetzt ... als Sie List<B>.Add(A);

Deshalb zu tun wäre in der Lage Sie alle Arten Sicherheit verlieren würde Generika.

1

Eigentlich kann man dieses Problem lösen, indem GetForShipWeight eine generische Funktion:

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

Eine alternative Lösung, die auch für .NET 3,5

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