Come vengono implementate la covarianza e la controvarianza generiche in C # 4.0?


106

Non ho partecipato al PDC 2008, ma ho sentito alcune notizie che C # 4.0 è stato annunciato per supportare la covarianza e la controvarianza generiche. Cioè, List<string>può essere assegnato a List<object>. Come potrebbe essere?

Nel libro di Jon Skeet C # in Depth , viene spiegato perché i generici C # non supportano la covarianza e la controvarianza. Serve principalmente per scrivere codice sicuro. Ora, C # 4.0 è stato modificato per supportarli. Porterebbe il caos?

Qualcuno sa che i dettagli su C # 4.0 possono dare qualche spiegazione?


Ecco un buon articolo che copre le imminenti implementazioni di covarianza e controvarianza su delegati e interfacce in C # 4.0: LINQ Farm: Covariance e controvarianza in C # 4.0
CMS

Anders Noråse spiega in C # 4.0 - Covarianza e controvarianza il concetto e mostra che è già supportato oggi in IL a partire da .NET 2.0.
Thomas Freudenberg il

Risposte:


155

La varianza sarà supportata solo in modo sicuro , utilizzando infatti le capacità che il CLR già possiede. Quindi gli esempi che fornisco nel libro del tentativo di utilizzare List<Banana>un fileList<Fruit> (o qualunque cosa fosse) ancora non funzioneranno, ma alcuni altri scenari funzioneranno.

In primo luogo, sarà supportato solo per interfacce e delegati.

In secondo luogo, richiede che l'autore dell'interfaccia / delegato decori i parametri di tipo come in(per controvarianza) o out(per covarianza). L'esempio più ovvio è IEnumerable<T>che ti permette solo di prendere valori "fuori" da esso - non ti permette di aggiungerne di nuovi. Quello diventerà IEnumerable<out T>. Ciò non danneggia affatto la sicurezza dei tipi, ma ti consente di restituire un IEnumerable<string>da un metodo dichiarato per tornare, IEnumerable<object>ad esempio.

La controvarianza è più difficile da fornire esempi concreti per l'utilizzo delle interfacce, ma è facile con un delegato. Tener conto diAction<T> : rappresenta solo un metodo che accetta un Tparametro. Sarebbe bello poter convertire senza problemi usando un Action<object>come un Action<string>- qualsiasi metodo che accetta un objectparametro andrà bene quando viene presentato con un stringinvece. Ovviamente, C # 2 ha già covarianza e controvarianza dei delegati in una certa misura, ma tramite una conversione effettiva da un tipo di delegato a un altro (creazione di una nuova istanza) - vedere P141-144 per esempi. C # 4 renderà questo più generico e (credo) eviterà di creare una nuova istanza per la conversione. (Sarà invece una conversione di riferimento.)

Spero che questo chiarisca un po 'le cose - fammi sapere se non ha senso!


3
Quindi, significa che se la classe è dichiarata come "List <out T>", NON dovrebbe avere una funzione membro come "void Add (T obj)"? Il compilatore C # 4.0 segnalerà un errore su questo, giusto?
Morgan Cheng,

1
Morgan: Questa è certamente la mia comprensione, sì.
Jon Skeet

4
ancora una volta una delle tue risposte qui su SO mi ha immediatamente aiutato a migliorare del codice. Grazie!
Mark

@ Ark-kun: Sì, ne sono consapevole. Quindi "ancora non funzionerà" nella stessa frase. (E sono anche consapevole dei motivi.)
Jon Skeet,

@JonSkeet È corretto affermare che "puoi usare solo a List<Banana>come IList<Fruit>" come ha detto @ Ark-kun? Se è così, come è possibile, anche se il parametro type IList<T>dell'interfaccia non è definito come covariante (no out T, ma semplicemente T).
gehho

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.