2012-04-27 42 views
14

Tôi có lớp/giao diện sau:Thực hiện giao diện chung lồng nhau

// Model 
public class A : IA { } 
// ModelLogic 
public class B : IB<A> { } 

// Model Interface 
public interface IA { } 
// ModelLogic Interface 
public interface IB<T> where T : IA { } 

tôi cố gắng tạo ra một trường hợp mới sử dụng đoạn mã sau:

IB<IA> foo = new B(); 

Tôi nhận được lỗi sau:

Cannot implicitly convert type 'B' to 'IB<IA>'. An explicit conversion exists (are you missing a cast?) 

Ai đó có thể giải thích tại sao điều này là không thể?

+0

Bạn đang sử dụng phiên bản C# nào? – Oded

+3

[Câu hỏi thường gặp về hiệp phương sai và câu hỏi thường gặp] (http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx) và [loạt blog này] (http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/) bởi Eric Lippert – Oded

Trả lời

41

OK, chúng ta hãy thay thế A với Fish, IA với IAnimal, B với Aquarium, và IB<T> với IContainer<T>. Và chúng ta sẽ thêm một thành viên IContainer<T> và thực hiện thứ hai của IAnimal:

// Model 
public class Fish : IAnimal { } 
public class Tiger : IAnimal { } 
// ModelLogic 
public class Aquarium : IContainer<Fish> 
{ 
    public Fish Contents { get; set; } 
} 

// Model Interface 
public interface IAnimal { } 
// ModelLogic Interface 
public interface IContainer<T> where T : IAnimal 
{ 
    T Contents { get; set; } 
} 

IContainer<IAnimal> foo = new Aquarium(); // Why is this illegal? 
foo.Contents = new Tiger(); // Because this is legal! 

Bạn có thể đặt một Tiger vào foo - foo được gõ như một container có thể chứa bất kỳ động vật. Nhưng bạn chỉ có thể đặt một con cá vào một bể cá. Vì các hoạt động bạn có thể thực hiện hợp pháp trên Aquariumkhác nhau so với các thao tác bạn có thể thực hiện trên IContainer<IAnimal>, các loại này không tương thích.

Các tính năng mà bạn muốn được gọi là chung giao diện hiệp phương sai và nó hỗ trợ bởi C# 4, nhưng bạn phải chứng minh cho trình biên dịch mà bạn sẽ không bao giờ đặt một con hổ vào bể cá của bạn. Những gì bạn muốn làm là:

// Model 
public class A : IA { } 
// ModelLogic 
public class B : IB<A> { } 

// Model Interface 
public interface IA { } 
// ModelLogic Interface 
public interface IB<out T> where T : IA { } 

Chú ý chú thích hiệp phương sai trên IB. Điều này out có nghĩa là T chỉ có thể được sử dụng làm đầu ra, không phải là đầu vào. Nếu T chỉ là một đầu ra thì không có cách nào để một người nào đó để đặt một con hổ vào bể cá đó bởi vì không có "đưa vào" tài sản hoặc phương pháp có thể.

Tôi đã viết một số bài viết trên blog trong khi chúng tôi đã thêm tính năng đó vào C#; nếu bạn quan tâm đến những cân nhắc thiết kế mà đi vào tính năng này, xem:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

+0

Phương sai không hợp lệ: Thông số loại 'T' phải có giá trị bất biến hợp lệ trên 'xx.IContainer .Contents'. 'T' là biến thể. \t Tôi nhận được lỗi này. Tôi mới vào công cụ biến đổi. Lỗi này có nghĩa là gì? – Sandeep

+3

@Sandeep: Bạn bằng cách nào đó đang sử dụng T ở vị trí đầu vào khi bạn đã nói rằng bạn sẽ chỉ sử dụng nó ở vị trí đầu ra. Có phải 'Nội dung' là một thuộc tính có bộ setter không? Nếu đó là sau đó rõ ràng T đang được sử dụng ở một vị trí đầu vào, và do đó giao diện không thể được thực hiện covariant trong T. –

+0

Cảm ơn Eric. Điều đó giải quyết nó. – Sandeep

1

Để khắc phục mã của bạn, chỉ cần thay đổi

public interface IB<T> where T : IA { } 

để

public interface IB<out T> where T : IA { } 
+0

awww, Eric đánh tôi với nó :) – CodingWithSpike

0

Nó không phải dễ dàng để xem khi nào bạn có giao diện trống.Hãy xem xét bạn có một phương pháp M trong giao diện IB:

public interface IB<T> where T : IA 
{ 
    void M(T t); 
} 

Và đây là thực hiện B:

public class B : IB<A> 
{ 
    public void M(A t) 
    { 
     // only object of type A accepted 
    } 
} 

Sau đó, bạn có đối tượng C, mà còn thực hiện IA:

public class C : IA { } 

Vì vậy, , nếu mã của bạn có thể, sau đó bạn có thể gọi:

IB<IA> foo = new B(); 
foo.M(new C()); 

Vấn đề là lớp B chỉ chấp nhận các đối tượng thuộc loại A. Lỗi!

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