2011-09-01 21 views
11

El siguiente código funciona:Lista de fundición <x> a la lista <y>

List<JsonStock> stock = new List<JsonStock>(); 

foreach(tblStock item in repository.Single(id).tblStocks)     
    stock.Add((JsonStock) item); 

Así que, naturalmente, se podría pensar que este código podría funcionar también:

List<JsonStock> stock = repository.Single(id).tblStocks.Cast<JsonStock>().ToList() 

pero me sale el error Invalid cast operation - ¿alguien ¿Sabes por qué podría pasar eso?

ACTUALIZACIÓN

tblStocks es una lista de LINQ a SQL objeto, tblStock.
JsonStock es una versión simplificada de la clase tblStock y se devuelve a una página web como un objeto JSON.

El siguiente operador fue construido para hacer el casting:

public partial class tblStock{ 
    public static explicit operator JsonStock(tblStock stock){ 
     JsonStock item = new JsonStock 
     { 
      boxes = stock.boxes, 
      boxtype = stock.tblBoxType.name, 
      boxtype_id = stock.boxtype_id, 
      grade = stock.grade, 
      packrate = stock.packrate, 
      weight = stock.weight 
     }; 

     return item; 
    } 
} 
+3

cómo es el tipo de 'tblStocks' definido? –

+0

Solo una idea, no estoy seguro de esto: 'repository.Single (id) .tblStocks' devuelve una matriz o lista de' JsonStock', por lo que cuando intentas invocar 'JsonStock' se queja ... – Marco

+0

@Marco - no no debería quejarse –

Respuesta

6

Cast se utiliza para cambiar una colección no genérica en un genérico, es decir, se realiza una operación unboxing. No puede usarse de la manera que desee.
Al echar un vistazo a la implementación de Cast y la CastIterator que utiliza, ya ves, que toma un objeto y lo convierte en el tipo especificado:

foreach (object current in source) 
{ 
    yield return (TResult)current; 
} 

Esto sólo funciona si current realmente es un TResult . No se aplican conversiones personalizadas en este caso.
Este es el comportamiento por defecto, puede probar usted mismo:

double d = 0.0; 
object tmp = d; 
int i = (int)tmp; // throws the same exception you are getting 

Lo que se quiere se logra mejor con una simple Select si tblStocks es un enumerable genérica:

List<JsonStock> stock = repository.Single(id).tblStocks 
            .Select(x => (JsonStock)x).ToList(); 

O, si tblStocks es un enumerable no genérica, es necesario combinar Cast y Select:

List<JsonStock> stock = repository.Single(id).tblStocks.Cast<tblStock>() 
            .Select(x => (JsonStock)x).ToList(); 

Esto primero desempaquetará los objetos en tblStocks en su tipo real (tblStock) y luego lo lanzará al tipo que desee (JsonStocks).

+2

+1 para obtener el – UrbanEsc

1

En lugar de utilizar moldeada, considerar el uso de OfType. En Cast, si el elemento que está procesando no es el tipo de documento eliminado, obtendrá la InvalidCastException. Con OfType, atrapará el lanzamiento no válido y solo devolverá los elementos que realmente son del tipo que está buscando.

List<JsonStock> stock = repository.Single(id).tblStocks.OfType<JsonStock>().ToList() 

Si regresa listas vacías sin embargo, sospecharía que sus tblStocks en realidad no va a regresar JsonStocks y que están tratando de proyectar algún otro tipo (tblStock?) En un DTO (JsonStock). Si el último es el caso, debe usar Seleccionar para proyectar en el nuevo tipo del tipo subyacente.

List<JsonStock> stock = repository.Single(id).tblStocks 
         .Select(stock => new JsonStock 
          { 
           Id = stock.Id, 
           Val1 = stock.Val1, 
           Val2 = stock.Val2, 
           ... 
          } 
         .ToList(); 
1
  • tblStocks.Cast<JsonStock>() realiza un lanzamiento.
  • (JsonStock) item realiza una conversión o aplica una conversión personalizada.

Dado que tblStock es una clase LINQ a SQL y JsonStock es una clase personalizada creada por usted, ninguno es un subtipo de la otra. Por lo tanto, no puedes elegir entre los dos.

Para solucionar este problema, puede utilizar la cláusula de Select de LINQ y convertir manualmente los elementos:

List<JsonStock> stock = repository.Single(id).tblStocks 
    .Select(item => (JsonStock) item).ToList(); 
2

operadores de conversión implícitos y explícitos son ignored by Cast. En su caso esto significa que

public static explicit operator JsonStock(tblStock stock) 

es ignorado por moldeada que sin embargo no se tienen en cuenta en el caso foreach

+0

más completo ¿Quién lo dice? Si eso fuera cierto, 'Enumerable.Cast () 'no tendría ningún sentido. http://msdn.microsoft.com/en-us/library/bb341406.aspx no contiene información para respaldar su reclamo. – VVS

+0

@VVS: no entiende el propósito de 'Enumerable.Cast ()'. La entrada es enumerable no genérica. El resultado es un enumerable genérico. El propósito de este método de extensión es crear un enumerable sólido a partir de un enumerable no genérico que conozca el tipo de los objetos. Ver mi respuesta para más detalles. –

+0

@VVS Si se lee cuidadosamente, ese enlace sí contiene información para respaldar mi reclamo, como lo hace el enlace en mi respuesta. El enlace que ha proporcionado habla sobre los operadores de _cast_ lo anterior es un operador _conversión_. La sintaxis para usar ambos es la misma (SomeType) pero eso no los hace iguales. Así que realmente no entiendo tu voto –

1

Ahhh, las maravillas de sobrecargas de operadores explícitos.

Para solucionar su problema, es posible que desee llamar a un Seleccionar de antemano.

List<JsonStock> stock = repository.Single(id).tblStocks.Select(x => (JsonStock)x).ToList() 

Sin embargo, yo diría que esta sobrecarga de operador es algo de lo que debe deshacerse. Considere reemplazarlo con un constructor de copia como aplicación

class JsonStock 
{ 
    public JsonStock(tblStock other) 
    { 
      // copy values here 
    } 
} 
+0

+1 Gracias por la solución: P – Jimbo

Cuestiones relacionadas