Nie uczestniczyłem w PDC 2008, ale usłyszałem wiadomości, że C # 4.0 ma obsługiwać kowariancję i kontrwariancję rodzajową. Oznacza to, że List<string>
można przypisać do List<object>
. Jak to możliwe?
W książce Jona Skeeta C # in Depth wyjaśniono, dlaczego typy generyczne języka C # nie obsługują kowariancji i kontrawariancji. Służy głównie do pisania bezpiecznego kodu. Teraz zmieniono C # 4.0, aby je obsługiwał. Czy przyniesie chaos?
Czy ktoś zna szczegóły dotyczące języka C # 4.0, może udzielić wyjaśnienia?
c#
c#-4.0
covariance
contravariance
generic-variance
Morgan Cheng
źródło
źródło
Odpowiedzi:
Wariancja będzie obsługiwana tylko w bezpieczny sposób - w rzeczywistości przy użyciu umiejętności, które już posiada CLR. Tak więc przykłady, które podam w książce, jak próbować użyć a
List<Banana>
jakoList<Fruit>
(lub cokolwiek to było), nadal nie będą działać - ale kilka innych scenariuszy będzie działać.Po pierwsze, będzie obsługiwane tylko w przypadku interfejsów i delegatów.
Po drugie, wymaga od autora interfejsu / delegata dekoracji parametrów typu jako
in
(dla kontrawariancji) lubout
(dla kowariancji). Najbardziej oczywistym przykładem jest to,IEnumerable<T>
że pozwala tylko „wyjąć” z niego wartości - nie pozwala na dodawanie nowych. To się stanieIEnumerable<out T>
. To wcale nie szkodzi bezpieczeństwu typów, ale pozwala na przykład zwrócić wartośćIEnumerable<string>
z metody zadeklarowanej do zwróceniaIEnumerable<object>
.Kontrawariancja jest trudniejsza do podania konkretnych przykładów użycia interfejsów, ale z delegatem jest to łatwe. Rozważ
Action<T>
- to po prostu reprezentuje metodę, która przyjmujeT
parametr. Byłoby miło móc bezproblemowo konwertować, używającAction<object>
jako anAction<string>
- każda metoda, która przyjmujeobject
parametr, będzie w porządku, gdy zostanie przedstawionastring
zamiast. Oczywiście C # 2 ma już w pewnym stopniu kowariancję i kontrawariancję delegatów, ale poprzez rzeczywistą konwersję z jednego typu delegata na inny (tworzenie nowej instancji) - zobacz przykłady w P141-144. C # 4 uczyni to bardziej ogólnym i (wierzę) pozwoli uniknąć tworzenia nowej instancji konwersji. (Zamiast tego będzie to konwersja referencyjna).Mam nadzieję, że to trochę wyjaśnia - daj mi znać, jeśli to nie ma sensu!
źródło
List<Banana>
jakoIList<Fruit>
”, jak powiedział @ Ark-kun? Jeśli tak, jak to możliwe, chociaż parametr typuIList<T>
interfejsu nie jest zdefiniowany jako kowariantny (nieout T
, ale po prostuT
).Nie żeby Jon jeszcze tego nie opisał, ale oto kilka linków do blogów i filmów Erica Lipperta. Wykonuje dobrą robotę, wyjaśniając to przykładami.
https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and-contravariance-in-c-part-one/
Filmy:
https://www.youtube.com/watch?v=3MQDrKbzvqU
https://www.youtube.com/watch?v=XRIadQaBYlI
https://www.youtube.com/watch?v=St9d2EDZfrg
źródło