2013-07-12 19 views
5

Durante la lettura di un section di un articolo su covarianza e controvarianza su Wikipedia, mi sono imbattuto nel seguente, la frase in grassetto:covarianza e controvarianza con C# Array

in primo luogo considerare il costruttore tipo array: dal tipo Animal siamo può fare il tipo Animal[] ("array di animali"). Dovremmo trattare questo come

  • covariante: un Cat[] è un Animal[]
  • controvariante: un Animal[] è un Cat[]
  • o nessuno dei due (invariante)?

Se si desidera evitare errori di tipo e la matrice supporta sia elementi di lettura che di scrittura, solo la terza scelta è sicura. Chiaramente, non tutti gli Animal[] possono essere trattati come se fossero Cat[], poiché un client che legge dall'array si aspetta un Cat, ma un Animal[] può contenere ad es. a Dog. Quindi la regola controvariante non è sicura.

Al contrario, uno Cat[] non può essere considerato come Animal[]. Dovrebbe essere sempre possibile inserire Dog in Animal[]. Con gli array covarianti non si può garantire che questo sia sicuro, dal momento che il backing store potrebbe effettivamente essere una schiera di gatti. Quindi anche la regola covariante non è sicura: il costruttore di array dovrebbe essere invariato. Si noti che questo è solo un problema per gli array mutabili; la regola covariante è sicura per gli array immutabili (di sola lettura).

Capisco il concetto; Voglio solo un esempio di come "non può essere garantito che sia sicuro" in C#.

+0

http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx – SLaks

+1

Non so perché questo è chiuso come duplicato della domanda collegata. Una q più correlata: [why-is-array-co-variance-considered-so-orrible] (http://stackoverflow.com/questions/4317459/why-is-array-co-variance-considered-so-horrible) – nawfal

risposta

15

Non è sicuro in fase di compilazione. In altre parole, c'è un codice che è legale dalle regole del linguaggio, ma fallisce al momento dell'esecuzione, senza alcun cast esplicito per dare un grande segnale di avvertimento di "questo potrebbe fallire". Il CLR si assicura che solo le scritture valide riescano a esecuzione tempo. Per esempio:

string[] strings = new string[1]; 
object[] objects = strings; 
objects[0] = new object(); 

Che sarà un'eccezione (ArrayTypeMismatchException) in fase di esecuzione. L'alternativa sarebbe stata consentire al momento dell'esecuzione, a cui punto strings[0] sarebbe stato un riferimento a un oggetto non stringa, che sarebbe chiaramente negativo.

Vedi anche recenti pubblicazioni:

+0

Quando dici "Il CLR si assicura che sia sicuro al momento dell'esecuzione". Ti riferisci al fatto che genera un'eccezione? Questo è il modo per assicurarti che sia sicuro al momento dell'esecuzione? –

+0

@MichaelPerrenoud: Sì, esattamente. Modificherò per chiarirlo. –

+0

Fantastico, grazie, volevo solo assicurarmi di aver capito! –

0

Penso che quello che stanno cercando di dire è:

Dog dog = new Dog(); 
Cat[] cats = new Cat[] { catOne, catTwo, catThree }; 
Animal[] animals = cats; 
animals.Add(dog); 

Linea 3 del presente codice non può essere legale perché si dovrebbe sempre essere in grado di fare la linea 4 (aggiunta di un Dog ad una serie di Animal s). Ma se la linea 3 era legale, la linea 4 non sarebbe legale (perché non è possibile aggiungere uno a un array di Cat s).

+0

Descrivi un modo in cui il team C# potrebbe averlo implementato - ma in realtà, riga 3 _viene compilato, e la linea 4 viene catturata in fase di esecuzione (tecnicamente, la riga 4 non viene compilata perché non esiste un metodo Add per un array --- ma gli animali [0] = il cane verrebbe catturato in fase di esecuzione.) – Hutch