Genel Kovaryans ve Kontra-varyans C # 4.0'da Nasıl Uygulanır?


106

PDC 2008'e katılmadım, ancak C # 4.0'ın Genel kovaryansı ve ters varyansı desteklediğine dair bazı haberler duydum. Yani, List<string>atanabilir List<object>. Bu nasıl olabildi?

Jon Skeet'in C # in Depth adlı kitabında , C # jeneriklerinin neden kovaryansı ve ters varyansı desteklemediği açıklanıyor. Esas olarak güvenli kod yazmak içindir. Şimdi, C # 4.0 onları desteklemek için değiştirildi. Kaos getirir mi?

C # 4.0 ile ilgili ayrıntıları bilen var mı?


İşte C # 4.0'da temsilciler ve arabirimler üzerinde yaklaşan kovaryans ve ters varyans uygulamalarını kapsayan iyi bir makale: LINQ Farm: C # 4.0'da Kovaryans ve Kontravaryans
CMS

Anders Noråse, C # 4.0'da açıklıyor: Kavramı kovaryans ve zıt varyans , .NET 2.0'dan beri IL'de bugün zaten desteklendiğini gösteriyor.
Thomas Freudenberg

Yanıtlar:


155

Varyans, yalnızca güvenli bir şekilde desteklenecek - aslında, CLR'nin zaten sahip olduğu yetenekler kullanılarak. Bu nedenle, a'yı List<Banana>bir List<Fruit>(veya her neyse) olarak kullanmaya çalışma kitabında verdiğim örnekler hala işe yaramayacak - ancak diğer birkaç senaryo işe yarayacak.

İlk olarak, yalnızca arayüzler ve temsilciler için desteklenecektir.

İkinci olarak, arayüz / temsilcinin yazarının tip parametrelerini in(kontravans için) veya out(kovaryans için ) olarak dekore etmesini gerektirir . En bariz örnek, IEnumerable<T>yalnızca ondan değer "çıkarmanıza" izin verendir - yenilerini eklemenize izin vermez. Bu olacak IEnumerable<out T>. Bu, tür güvenliğine hiç zarar vermez, ancak örneğin IEnumerable<string>return IEnumerable<object>için bildirilen bir yöntemden bir döndürmenize izin verir .

Contravariance, arayüzleri kullanmak için somut örnekler vermek daha zordur, ancak bir delege ile kolaydır. Düşünün Action<T>- bu sadece bir Tparametre alan bir yöntemi temsil eder . Sorunsuz dönüştürmek bir kullanabilmek için güzel olurdu Action<object>bir şekilde Action<string>bir alan herhangi bir yöntemle - objectparametre bir ile sunulan ne zaman cezası olacak stringyerine. Elbette, C # 2 zaten bir dereceye kadar delegelerin kovaryansına ve kontravansına sahiptir, ancak bir delege türünden diğerine gerçek bir dönüşüm yoluyla (yeni bir örnek oluşturma) - örnekler için bkz. P141-144. C # 4 bunu daha genel hale getirecek ve (inanıyorum) dönüşüm için yeni bir örnek oluşturmaktan kaçınacaktır. (Bunun yerine bir referans dönüştürme olacaktır.)

Umarım bu biraz açıklığa kavuşur - mantıklı değilse lütfen bana bildirin!


3
Öyleyse, sınıfın "List <out T>" olarak bildirilmesi durumunda "void Add (T obj)" gibi bir üye işlevi OLMAMASI gerektiği anlamına mı gelir? C # 4.0 derleyici bu konuda hata bildirecek, değil mi?
Morgan Cheng

1
Morgan: Kesinlikle benim anlayışım, evet.
Jon Skeet

4
yine burada SO'daki yanıtlarınızdan biri hemen bazı kodları geliştirmeme yardımcı oldu. Teşekkür ederim!
Mark

@ Ark-kun: Evet, bunun farkındayım. Dolayısıyla aynı cümlede "hala çalışmayacak". (Ve nedenlerinin de farkındayım.)
Jon Skeet

@JonSkeet @ Ark- kun'un dediği gibi "a'yı sadece bir List<Banana>olarak kullanabilirsin" doğru IList<Fruit>mu? Eğer öyleyse, IList<T>arayüzün tür parametresi ortak değişken olarak tanımlanmasa da (hayır out T, ancak basitçe T) bu nasıl mümkün olabilir ?
gehho

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.