2010-10-31 34 views
6

Phải có điều gì đó cơ bản về giao diện/generics mà tôi chưa học được. Tôi hy vọng sẽ tìm hiểu nó ngay bây giờ.Tại sao danh sách Giao diện không thể sử dụng loại triển khai?

Dưới đây là kịch bản:

Tôi có giao diện này và lớp:

public interface IInterface 
{ 
    string TestValue { get; set; } 
} 

public class RealValue: IInterface 
{ 
    public string TestValue { get; set; } 
} 

Nếu tôi tạo ra một phương pháp như thế này nó biên dịch tốt:

public class RandomTest: IMethodInterface 
{ 
    public IInterface GetRealValue() 
    { 
     RealValue realValue = new RealValue(); 
     return realValue; 
    } 
} 

Lưu ý rằng tôi trả về một đối tượng thực hiện giao diện.

Bây giờ, nếu tôi thêm vào lớp RandomTest một phương thức trả về danh sách sau đó nó không hoạt động nữa:

public List<IInterface> GetRealValues() 
{ 
    List<RealValue> realValues = new List<RealValue>(); 
    return realValues; // ERROR Here <- says it can't convert to a List<IInterface> 
} 

Vì vậy, tôi đoán là Generics không thể con số này ra, nhưng tại sao?

Có cách nào khác không? Bạn làm gì khi giá trị trả lại của phương thức trên bị khóa vì bạn đang triển khai giao diện như sau:

public interface IMethodInterface 
{ 
    IInterface GetRealValue(); 
    List<IInterface> GetRealValues(); // Can't just convert the return types to a concrete 
             // class because I am implementing this. This 
             // interface is in a separate project that does not 
             // have the concrete classes. 
} 

Có hy vọng nào không? Bạn sẽ làm gì?

Trả lời

9

Lý do cho điều này là List<RealValue> là một loại cụ thể, không kế thừa List<IInterface>, do đó không thể chuyển đổi.

Tuy nhiên, trong .NET 4.0 bạn đang gặp may. Giao diện IEnumerable<out T> xác định rằng T thể lớp, hay một lớp cơ sở, vì vậy bạn có thể thay đổi phương pháp của bạn:

IEnumerable<IInterface> GetRealValues(); 

trên NET 4.0. Lưu ý rằng điều này chỉ hoạt động bởi vì IEnumerable có từ khóa out được chỉ định trên thông số mẫu.

Từ khóa out nghĩa hai điều:

  1. Các loại trước đó bạn đặt các từ khóa out chỉ có thể được sử dụng với nhiều loại mà đi ra khỏi lớp. Vì vậy, public T MyMethod() được cho phép, nhưng public void MyMethod(T myParam) không được phép, bởi vì điều này đi vào lớp học;

  2. Do hạn chế này, .NET biết rằng T có thể được chuyển thành mọi thứ kế thừa từ T. Do sự hạn chế, điều này được đảm bảo là một hoạt động an toàn.

+0

Điều này có vẻ tốt đẹp. Tôi sẽ phải đào sâu hơn để hiểu những gì 'out' có nghĩa là cho một param loại chung chung. Dù bằng cách nào, tôi đã thử nó và nó đã làm việc. – Vaccano

+0

Mở rộng câu trả lời bằng một chút thông tin liên quan đến từ khóa 'out'. –

+0

Ngọt ngào! Cảm ơn câu trả lời mở rộng! – Vaccano

1

Không thể sử dụng List<RealValue> thay cho số List<IInterface>. Nếu được phép, người gọi sẽ có thể Thêm IInterface vào danh sách được trả về thuộc loại không phải là RealValue.

3

Lưu ý rằng nếu bạn có thể chuyển đổi List<RealValue> thành List<IInterface>, bạn có thể gọi .Add(anyObjectImplementingIInterface) không thể hoạt động. Tuy nhiên, bạn có thể sử dụng .Cast<IInterface>().ToList().

Các vấn đề liên quan