UPDATE: Ho usato questa domanda come base per un blog, qui:
http://blogs.msdn.com/ericlippert/archive/2009/09/24/why-is-covariance-of-value-typed-arrays-inconsistent.aspx
Vedere i commenti del blog per una discussione estesa di questa edizione. Grazie per la bella domanda!
Hai inciampato attraverso una contraddizione interessante e sfortunato tra il sistema di tipo CLI e il sistema C# tipo.
CLI ha il concetto di "compatibilità di assegnazione". Se un valore x del tipo di dati noto S è "assegnazione compatibile" con una particolare posizione di memoria y del tipo di dati noto T, allora è possibile memorizzare x in y. In caso contrario, fare ciò non è un codice verificabile e il verificatore lo rifiuterà.
Il sistema di tipo CLI dice, ad esempio, che i sottotipi di tipo di riferimento sono compatibili con i supertipi di tipo di riferimento. Se si dispone di una stringa, è possibile memorizzarla in una variabile di tipo oggetto, poiché entrambi sono tipi di riferimento e la stringa è un sottotipo di oggetto. Ma il contrario non è vero; i supertipi non sono compiti compatibili con i sottotipi. Non puoi incollare qualcosa che solo noto per essere oggetto in una variabile di tipo string senza prima lanciarlo.
Fondamentalmente "assegnazione compatibile" significa "ha senso inserire questi bit esatti in questa variabile". L'assegnazione dal valore di origine alla variabile di destinazione deve essere "preservazione della rappresentazione". Vedere il mio articolo su questo per i dettagli:
http://ericlippert.com/2009/03/03/representation-and-identity/
Una delle regole della CLI è "se X è compatibile con l'assegnazione Y, allora X [] è compatibile con l'assegnazione Y []".
In altre parole, gli array sono covarianti rispetto alla compatibilità dell'assegnazione. Questo è in realtà un tipo di covarianza interrotto; vedere il mio articolo su questo per i dettagli.
http://blogs.msdn.com/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx
che non è una regola di C#. La regola di covarianza dell'array di C# è "se X è un tipo di riferimento convertibile implicitamente al tipo di riferimento Y, quindi X [] è implicitamente convertibile in Y []". Questa è una regola sottilmente diversa, e quindi la tua situazione confusa.
Nella CLI, uint e int sono compatibili dell'assegnazione. Ma in C#, la conversione tra int e uint è ESPLICITA, non IMPLICIT, e questi sono tipi di valore, non tipi di riferimento. Quindi in C# non è legale convertire un [] in un uint [].
Ma è legale nella CLI. Quindi ora ci troviamo di fronte a una scelta.
1) L'implementazione "è" in modo che quando il compilatore non è in grado di determinare la risposta staticamente, in realtà chiama un metodo che controlla tutte le regole C# per la convertibilità che preserva l'identità. Questo è lento e il 99,9% delle volte corrisponde a quello che sono le regole CLR. Ma prendiamo il colpo di prestazioni in modo da essere al 100% conformi alle regole di C#.
2) Implementare "è" in modo tale che quando il compilatore non è in grado di determinare la risposta in modo statico, esegue il controllo di compatibilità dell'assegnazione CLR incredibilmente veloce e convive con ciò che un uint [] è un int [], anche se in realtà non sarebbe legale in C#.
Abbiamo scelto quest'ultimo. È un peccato che C# e le specifiche CLI non siano d'accordo su questo punto, ma siamo disposti a convivere con l'incoerenza.
Ottima lettura. Grazie per la risposta. –
Ciao Eric, per curiosità, voi ragazzi avete deciso di accettare questa incoerenza o non era prevista prima? Mi stavo solo chiedendo. –
Cancellato il mio post in ossequio a una risposta molto migliore e approfondita. – LBushkin