2009-03-23 25 views
6

Ai đó có thể giải thích cho tôi tại sao trong .NET 2.0 nếu tôi có một giao diện, IPackable và một lớp thực hiện giao diện OrderItem, khi tôi có phương thức lấy số List<IPackable>, hãy chuyển vào danh sách List<OrderItem> không hoạt động?.NET Casting Generic List

Có ai biết cách tôi có thể thực hiện chức năng này không?

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

Các mã sau đây không hoạt động.

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

Xin vui lòng gửi mã có liên quan và những gì rắc rối bạn cụ thể đang có (lỗi xây dựng, lỗi thời gian chạy, v.v.). – Misko

Trả lời

7

Câu trả lời của JMD là chính xác. Để khắc phục, bạn có thể thử này:

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

Hoặc, nếu danh sách phải được đánh máy mạnh mẽ như OrderItems, thì đây (3,0 chỉ, xin lỗi):

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

JMD là một nửa chính xác. Trong thực tế, nó hoàn toàn không chính xác để nói rằng chúng tôi sẽ có thể đúc một danh sách chung với C# 4.0. Đúng là hiệp phương sai và contravariance sẽ được hỗ trợ trong C# 4.0 nhưng nó sẽ chỉ hoạt động với giao diện và đại biểu và sẽ có rất nhiều ràng buộc. Do đó, nó sẽ không hoạt động với List.

Lý do rất đơn giản.

Nếu B là một phân lớp của A, chúng tôi không thể nói rằng List<B> là một phân lớp của List<A>.

Và đây là lý do.

List<A> cho thấy một số phương pháp hiệp phương sai (trả về giá trị) và một số phương pháp contravariances (chấp nhận giá trị làm tham số).

ví dụ:

  • List<A> lộ Add(A);
  • List<B> lộ Add(B);

Nếu List<B> thừa hưởng từ List<A> ... hơn bạn sẽ có thể làm List<B>.Add(A);

Vì vậy, bạn sẽ mất tất cả các loại an toàn generics.

1

Trên thực tế, bạn có thể giải quyết việc này bằng cách làm cho GetForShipWeight một hàm tổng quát:

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

Một giải pháp thay thế mà cũng làm việc cho NET 3,5

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