Phương sai Chung & Phương sai Tương phản được triển khai như thế nào trong C # 4.0?


106

Tôi đã không tham dự PDC 2008, nhưng tôi đã nghe một số tin tức rằng C # 4.0 được công bố để hỗ trợ hiệp phương sai Chung và phương sai trái ngược. Đó là, List<string>có thể được chỉ định cho List<object>. Làm thế nào mà có thể được?

Trong cuốn sách C # in Depth của Jon Skeet , người ta giải thích lý do tại sao C # generic không hỗ trợ hiệp phương sai và phương sai trái ngược. Nó chủ yếu để viết mã an toàn. Bây giờ, C # 4.0 đã thay đổi để hỗ trợ chúng. Nó sẽ mang lại sự hỗn loạn?

Bất kỳ ai biết chi tiết về C # 4.0 có thể đưa ra một số lời giải thích?


Đây là một bài viết tốt mà bìa hiệp phương sai và contra-variance triển khai sắp tới trên đại biểu và giao diện trong C # 4.0: LINQ trại: Hiệp phương sai và Contravariance trong C # 4.0
CMS

Anders Noråse giải thích trong C # 4.0 - Hiệp phương sai và phương sai tương phản về khái niệm và cho thấy rằng ngày nay nó đã được hỗ trợ trong IL kể từ .NET 2.0.
Thomas Freudenberg 30/10/08

Câu trả lời:


155

Phương sai sẽ chỉ được hỗ trợ một cách an toàn - trên thực tế, bằng cách sử dụng các khả năng mà CLR đã có. Vì vậy, các ví dụ tôi đưa ra trong cuốn sách về việc cố gắng sử dụng a List<Banana>như một List<Fruit>(hoặc bất cứ điều gì đó là) vẫn sẽ không hoạt động - nhưng một số trường hợp khác sẽ làm được.

Thứ nhất, nó sẽ chỉ được hỗ trợ cho giao diện và đại biểu.

Thứ hai, nó yêu cầu tác giả của giao diện / đại biểu trang trí các tham số kiểu như in(đối với tương phản) hoặc out(đối với hiệp phương sai). Ví dụ rõ ràng nhất là IEnumerable<T>chỉ cho phép bạn lấy các giá trị "ra khỏi" nó - nó không cho phép bạn thêm các giá trị mới. Điều đó sẽ trở thành IEnumerable<out T>. Điều đó hoàn toàn không ảnh hưởng đến an toàn kiểu, nhưng cho phép bạn trả về một IEnumerable<string>từ một phương thức được khai báo để trả về IEnumerable<object>chẳng hạn.

Sự tương phản khó đưa ra các ví dụ cụ thể để sử dụng các giao diện, nhưng lại dễ dàng với một đại biểu. Hãy xem xét Action<T>- điều đó chỉ đại diện cho một phương thức nhận một Ttham số. Sẽ thật tuyệt nếu có thể chuyển đổi liền mạch bằng cách sử dụng một Action<object>như một Action<string>- bất kỳ phương thức nào có objecttham số sẽ ổn khi nó được trình bày với một stringthay thế. Tất nhiên, C # 2 đã có hiệp phương sai và phương sai của các đại biểu ở một mức độ nào đó, nhưng thông qua một chuyển đổi thực tế từ loại đại biểu này sang loại đại biểu khác (tạo một trường hợp mới) - xem ví dụ P141-144. C # 4 sẽ làm cho điều này chung chung hơn và (tôi tin rằng) sẽ tránh tạo một phiên bản mới cho chuyển đổi. (Thay vào đó, nó sẽ là một chuyển đổi tham chiếu.)

Hy vọng điều này sẽ làm sáng tỏ một chút - vui lòng cho tôi biết nếu nó không hợp lý!


3
Vì vậy, có nghĩa là nếu lớp được khai báo là "List <out T>" thì nó KHÔNG được có hàm thành viên như "void Add (T obj)"? Trình biên dịch C # 4.0 sẽ báo lỗi về điều đó, phải không?
Morgan Cheng

1
Morgan: Đó chắc chắn là sự hiểu biết của tôi, vâng.
Jon Skeet

4
nhưng một trong những câu trả lời của bạn ở đây trên SO đã ngay lập tức giúp tôi cải thiện một số mã. Cảm ơn bạn!
Đánh dấu

@ Ark-kun: Vâng, tôi biết điều đó. Do đó, "vẫn sẽ không hoạt động" trong cùng một câu. (Và tôi nhận thức được lý do, quá.)
Jon Skeet

@JonSkeet Có đúng là "bạn chỉ có thể sử dụng a List<Banana>as a IList<Fruit>" như @ Ark-kun đã nói không? Nếu vậy, làm thế nào điều này có thể thực hiện được, mặc dù tham số kiểu của IList<T>giao diện không được định nghĩa là hiệp phương sai (không out T, nhưng chỉ đơn giản T).
gehho

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.