Bagaimana Generic Covariance & Contra-variance Diimplementasikan dalam C # 4.0?


106

Saya tidak menghadiri PDC 2008, tetapi saya mendengar beberapa berita bahwa C # 4.0 diumumkan untuk mendukung kovarians Generik dan kontra-varian. Artinya, List<string>bisa ditugaskan ke List<object>. Bagaimana bisa?

Dalam buku Jon Skeet C # in Depth , dijelaskan mengapa C # generik tidak mendukung kovariansi dan kontra-varian. Ini terutama untuk menulis kode aman. Sekarang, C # 4.0 berubah untuk mendukung mereka. Apakah itu akan membawa kekacauan?

Adakah yang tahu detail tentang C # 4.0 dapat memberikan penjelasan?


Berikut adalah artikel bagus yang mencakup implementasi kovarians dan kontra-varians yang akan datang pada delegasi dan antarmuka di C # 4.0: LINQ Farm: Kovarian dan Kontravarian di C # 4.0
CMS

Anders Noråse menjelaskan dalam C # 4.0 - Kovarian dan kontra-varians konsep dan pertunjukan, bahwa itu sudah didukung hari ini di IL sejak .NET 2.0.
Thomas Freudenberg

Jawaban:


155

Varians hanya akan didukung dengan cara yang aman - pada kenyataannya, menggunakan kemampuan yang sudah dimiliki CLR. Jadi contoh yang saya berikan dalam buku tentang mencoba menggunakan a List<Banana>sebagai List<Fruit>(atau apa pun itu) tetap tidak akan berhasil - tetapi beberapa skenario lain akan berhasil.

Pertama, ini hanya akan didukung untuk antarmuka dan delegasi.

Kedua, memerlukan pembuat antarmuka / delegasi untuk menghias parameter tipe sebagai in(untuk kontradiksi) atau out(untuk kovarian). Contoh yang paling jelas adalah IEnumerable<T>yang hanya memungkinkan Anda mengambil nilai "keluar" darinya - tidak memungkinkan Anda menambahkan nilai baru. Itu akan menjadi IEnumerable<out T>. Itu tidak mengganggu keamanan tipe sama sekali, tetapi memungkinkan Anda mengembalikan IEnumerable<string>dari metode yang dideklarasikan untuk dikembalikan IEnumerable<object>misalnya.

Kontradiksi lebih sulit untuk memberikan contoh konkret untuk menggunakan antarmuka, tetapi mudah dengan delegasi. Pertimbangkan Action<T>- itu hanya mewakili metode yang mengambil Tparameter. Akan menyenangkan untuk dapat mengonversi dengan mulus menggunakan an Action<object>sebagai Action<string>- metode apa pun yang menggunakan objectparameter akan baik-baik saja ketika disajikan dengan a stringsebagai gantinya. Tentu saja, C # 2 sudah memiliki kovariansi dan kontradiksi delegasi sampai batas tertentu, tetapi melalui konversi aktual dari satu jenis delegasi ke jenis lainnya (membuat instans baru) - lihat P141-144 sebagai contoh. C # 4 akan membuat ini lebih umum, dan (saya percaya) akan menghindari membuat contoh baru untuk konversi. (Alih-alih, ini akan menjadi konversi referensi.)

Semoga ini sedikit menyelesaikannya - beri tahu saya jika tidak masuk akal!


3
Jadi, apakah itu berarti bahwa jika kelas tersebut dideklarasikan sebagai "List <out T>" maka TIDAK harus memiliki fungsi anggota seperti "void Add (T obj)"? Kompilator C # 4.0 akan melaporkan kesalahan itu, bukan?
Morgan Cheng

1
Morgan: Itu pasti pemahaman saya, ya.
Jon Skeet

4
sekali lagi salah satu jawaban Anda di SO telah segera membantu saya meningkatkan beberapa kode. Terima kasih!
Tandai

@ Ark-kun: Ya, saya tahu itu. Karenanya, "masih tidak akan berfungsi" dalam kalimat yang sama. (Dan saya juga mengetahui alasannya.)
Jon Skeet

@JonSkeet Apakah benar bahwa "Anda hanya dapat menggunakan List<Banana>sebagai IList<Fruit>" seperti yang dikatakan @ Ark-kun? Jika demikian, bagaimana ini mungkin, meskipun parameter tipe IList<T>antarmuka tidak didefinisikan sebagai kovarian (tidak out T, tetapi sederhana T).
gehho

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.