2011-12-06 41 views
8

Tôi cần một số lời khuyên/giúp đỡ về điều này, tôi không thể nhìn thấy gỗ từ cây nữa.C# Đúc generics (hiệp phương sai và contravariance?)

Đây là một chuỗi các lớp học hướng thẳng tiến hành một số giao diện sử dụng Generics.

Sau đó, tôi đang cố gắng để đúc các loại bê tông ví dụ:

MyGenericObject<SomeObject> _obj; 

IMyGenericObject<ISomeObject> _genObj = (IMyGenericObject<ISomeObject>)_obj; 

// không hợp lệ đúc

Tôi đã đọc một số bài viết về hiệp phương sai và contravariance nhưng không quá rõ ràng lý do tại sao wouldn này' t có thể, hoặc làm thế nào để làm tròn nó?


Vì vậy, trong ví dụ này:

public interface IMyObject<in T> where T : IBaseObject 
{ 
    T Activity { get; set; } 
} 

sẽ không hoạt động ...


.... bởi vì, bạn không thể nhận và thiết lập thuộc tính Hoạt động .

Trong ví dụ này, tôi cần phải làm:

public interface IMyObject<out T> where T : IBaseObject 
    { 
     T Activity { get; } 
    } 

hy vọng rằng sẽ giúp ai đó, và cảm ơn tất cả sự giúp đỡ!

+0

Vui lòng hiển thị định nghĩa giao diện của bạn –

Trả lời

9

Bạn chỉ có thể làm điều đó nếu bạn khai báo giao diện là có tham số covariant (out). Bạn chỉ có thể làm điều đó nếu tham số được sử dụng covariantly.

Ví dụ: nếu giao diện IMyGenericObject<T> có phương pháp tham số T, điều này ngăn bạn khai báo tham số dưới dạng biến thể. Ngược lại, nếu có phương thức trả về số T, điều đó ngăn bạn khai báo tham số là contravariant.

EDIT

Đáp lại bình luận của bạn về câu trả lời SLaks, tôi đang bị cám dỗ để lặp lại tất cả mọi thứ Eric Lippert đã từng viết trên đồng và contravariance. Xem http://blogs.msdn.com/b/ericlippert/archive/tags/Covariance+and+Contravariance/ và cũng câu trả lời của mình trong SO (gần đây nhất là https://stackoverflow.com/a/8380213/385844)

Để tóm tắt:

Bạn không thể đúc IList<string>-IList<object> vì nó là hợp pháp để vượt qua một FileInfo một IList<object>, nhưng nó không phải là hợp pháp để vượt qua nó đến một số IList<string>.

Bạn không thể cast một IList<object> một IList<string>, bởi vì đó là quy phạm pháp luật để lấy một mục từ một IList<string> và gán nó vào một tài liệu tham khảo chuỗi, nhưng một IList<object> có thể chứa một FileInfo, mà không thể được gán cho một chuỗi tài liệu tham khảo.

EDIT 2

Vì bạn hỏi để được tư vấn, nó cũng có thể chia giao diện của bạn vào đồng và các bộ phận contravariant. Để tiếp tục với ví dụ về danh sách, bạn có thể có các giao diện này

public interface ICovariantList<out T> 
{ 
    T this[int index] { get; } 
    //... 
} 

public interface IContravariantList<in T> 
{ 
    T this[int index] { set; } 
    void Add(T item); 
    //... 
} 

public class SomeList<T> : ICovariantList<T>, IContravariantList<T> 
{ 
    //... 
} 

Điều này cho phép bạn sử dụng lớp một cách có thể so sánh hoặc thay đổi tùy theo ngữ cảnh.

+0

được sắp xếp, cảm ơn bạn đã trợ giúp! – sambomartin

+0

@sambomartin bạn được chào đón. Một số lời khuyên trong EDIT 2. – phoog

+0

cảm ơn, tôi loại sussed rằng mặc dù tôi không cần setter cuối cùng anyway ... nhưng tôi biết cho thời gian tới! – sambomartin

4

Bạn cần khai báo giao diện là có tham số chung chung biến thể (out).

+2

biến thể là 'out'; contravariant là 'in'. Mnemonic: "o" cho covariant và out; "n" cho contravariant và in. – phoog

+0

ok, cảm ơn. Vấn đề tiếp theo mà tôi có là trình biên dịch báo cáo: "Lỗi 1 Phương sai không hợp lệ: Tham số kiểu 'xxx phải có giá trị bất biến hợp lệ trên' xxx là biến thể." Từ những gì tôi đã đọc, tôi cần phải làm cho giao diện chỉ đọc/bất biến. Tôi có một thuộc tính của IMyGenericInterface SomeObject SomeObjectInstance {get; set;} Bất kỳ ý tưởng nào? – sambomartin

+0

@sambomartin: Bạn cần hiểu cách phương sai hoạt động. Thuộc tính biến thể ghi có vốn không an toàn. – SLaks

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