2015-02-13 10 views
15

Se implemento un'interfaccia per un tipo di valore e provo a eseguirne il cast in un elenco del suo tipo di interfaccia, perché questo genera un errore mentre il tipo di riferimento viene convertito correttamente?Perché ToList <Interface> non funziona per i tipi di valore?

Questo è l'errore:

Cannot convert instance argument type System.Collections.Generic.List<MyValueType> to System.Collections.Generic.IEnumerable<MyInterfaceType>

devo usare esplicitamente il metodo Cast<T> per convertirlo, perché? Poiché IEnumerable è un'enumerazione di sola lettura attraverso una raccolta, non ha alcun senso per me che non possa essere trasmesso direttamente.

Ecco esempio di codice per dimostrare il problema:

public interface I{} 

    public class T : I{} 

    public struct V: I{} 

    public void test() 
    { 
     var listT = new List<T>(); 
     var listV = new List<V>(); 

     var listIT = listT.ToList<I>();  //OK 
     var listIV = listV.ToList<I>();  //FAILS to compile, why? 

     var listIV2 = listV.Cast<I>().ToList(); //OK 

    } 
+8

La varianza non funziona per le strutture. La varianza funziona per i tipi di riferimento perché le loro rappresentazioni (riferimenti/puntatori) mantengono i loro schemi di bit. –

+0

@TheodorosChatzigiannakis dovrebbe essere controverso, non varianza: http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29 – Fals

+6

@Fals: nessun tipo di varianza funziona per i tipi di valore. – SLaks

risposta

13

Variance (covariance or contravariance) non funziona per i tipi di valore, solo i tipi di riferimento:

Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type. (MSDN)

i valori contenuti all'interno di variabili di tipo riferimento sono riferimenti (per esempio, indirizzi) e gli indirizzi di dati hanno le stesse dimensioni e sono interpretati allo stesso modo, senza alcun cambiamento richiesto nei loro schemi di bit.

Al contrario, i valori contenuti nelle variabili di tipo valore non hanno la stessa dimensione o la stessa semantica. Usarli come tipi di riferimento richiede boxing e boxing richiede istruzioni specifiche del tipo che devono essere emesse dal compilatore. Non è pratico o efficiente (a volte forse nemmeno possibile) che il compilatore emetta istruzioni di boxe per ogni tipo possibile di tipo di valore, pertanto la varianza è completamente non consentita.

Fondamentalmente, la varianza è pratica grazie allo strato aggiuntivo di riferimento indiretto (il riferimento) dalla variabile ai dati effettivi. Poiché i tipi di valore non hanno questo livello di riferimento indiretto, mancano delle capacità di varianza.


Unire il sopra con il modo in operazioni LINQ funzionano:

Un Cast operazione upcasts/scatole tutti gli elementi (di accedervi attraverso il non generico IEnumerable, come lei ha sottolineato) e quindi verifica che tutti gli elementi in una sequenza può essere lanciato/unboxato correttamente al tipo fornito e poi fa esattamente questo. L'operazione ToList enumera la sequenza e restituisce un elenco da tale enumerazione.

Ognuno ha il proprio lavoro. Se (diciamo) ToList ha fatto il lavoro di entrambi, avrebbe il sovraccarico delle prestazioni di entrambi, che è indesiderabile per la maggior parte degli altri casi.

+3

In aumento. Ulteriori informazioni: L'estensione 'ToList ' è definita "on" "IEnumerable " ed è 'IEnumerable ' che è covariante qui. Il richiedente potrebbe fare "IEnumerable listAsI = listT;" direttamente anche a causa della stessa covarianza, ma che non eseguirà la copia (superficiale). –

+0

@JeppeStigNielsen Funziona! Ma ora mi sono perso: perché funziona quando lo assegno prima a "IEnumerable "? Se la covarianza funziona per l'assegnazione a 'IEnumerable ', perché non funziona implicitamente anche per '.ToList ()'? – Marwie

+0

E in più mi chiedo perché questo funzioni effettivamente, considerando quello che Theodoros Chatzigiannakis menziona nella sua risposta (nessuna variazione per i tipi di valore) avrei pensato che questo non funzionasse esattamente in questo caso. – Marwie

Problemi correlati