2012-09-17 7 views
12

dire che abbiamo 2 classi:Perché Enumerable.Cast non utilizza i cast definiti dall'utente?

public class A 
{ 
    public int a; 
} 

public class B 
{ 
    public int b; 

    public static implicit operator B(A x) 
    { 
     return new B { b = x.a }; 
    } 
} 

Allora perché

A a = new A { a = 0 }; 
B b = a; //OK 

List<A> listA = new List<A> { new A { a = 0 } }; 
List<B> listB = listA.Cast<B>().ToList(); //throws InvalidCastException 

Lo stesso per explicit dell'operatore.

P.S .: colata ciascun elemento manualmente (separetely) funziona

List<B> listB = listA.Select<A, B>(s => s).ToList(); //OK 

risposta

10

Il nome di Enumerable.Cast è fuorviante come suo scopo è quello di valori Unbox. Funziona su IEnumerable (non su IEnumerable<T>) per produrre un IEnumerable<T>. Se hai già un IEnumerable<T>Enumerable.Cast probabilmente non è il metodo che vuoi usare.

Tecnicamente, si sta facendo qualcosa di simile:

foreach(object obj in value) 
    yield return (T)obj; 

Se T è un'altra cosa rispetto al valore in scatola, questo porterà ad un InvalidCastException.

È possibile verificare questo comportamento da soli:

int i = 0; 
object o = i; 
double d1 = (double)i; // Works. 
double d2 = (double)o; // Throws InvalidCastException 

Hai due possibili soluzioni:

  1. Utilizzare Select(x => (B)x)
  2. Creare un metodo di estensione Cast che funziona su un IEnumerable<T> piuttosto che un IEnumerable.
+0

Quindi, fallisce perché prova a lanciare 'object' su' B', mentre ho definito un cast da 'A' a' B'? – horgh

+0

Fallisce, perché prima avrebbe bisogno di unbox l'oggetto 'a un' A' e di fare il cast. Qualcosa come '(B) (A) o'. Potresti forse definire un operatore di cast che funziona su 'object' invece che su' A', ma non avrebbe senso dato che la maggior parte delle istanze 'object' non sarebbero convertibili. –

+0

Ma è un 'Elenco ' dove 'T' è' A'. Non è un 'ArrayList' o' Lista '. Perché si verifica questo problema di boxing/unboxing? – horgh

Problemi correlati