2011-09-01 24 views
11

Il seguente codice funziona:Lista Casting <x> to List <y>

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

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

Così, naturalmente, si potrebbe pensare che questo codice dovrebbe funzionare anche:

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

ma ho l'errore di Invalid cast operation - Qualcuno sai perché potrebbe accadere?

UPDATE

tblStocks è una lista di LINQ to SQL oggetto, tblStock.
JsonStock è una versione semplificata della classe tblStock e viene restituita a una pagina Web come oggetto JSON.

Quanto segue operatore è stato costruito per fare il 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

come è definito il tipo di 'tblStocks'? –

+0

Solo un'idea, non sono sicuro di questo: 'repository.Single (id) .tblStocks' restituisce un array o un elenco di' JsonStock', quindi quando provi a lanciare come 'JsonStock' si lamenta ... – Marco

+0

@Marco - no non dovrebbe lamentarsi. –

risposta

6

Cast viene utilizzato per modificare un insieme non generico in una generica, cioè esso esegue un'operazione unboxing. Non può essere usato nel modo desiderato.
Quando si dispone di uno sguardo alla realizzazione del Cast e CastIterator utilizza, si vede, che si prende un oggetto e l'inserisce nel tipo specificato:

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

Funziona solo se current è davvero un TResult . In questo caso non vengono applicate conversioni personalizzate.
Questo è il comportamento di default, è possibile verificare da soli:

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

quello che vuoi è meglio realizzato con un semplice Select se tblStocks è un enumerabile generico:

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

O, se tblStocks è un enumerabile non generico, è necessario combinare Cast e Select:

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

In questo modo verranno innanzitutto annullati gli oggetti in tblStocks nel loro tipo reale (tblStock) e quindi trasmessi al tipo desiderato (JsonStocks).

+2

+1 per la maggior parte di – UrbanEsc

1

Invece di usare Fusioni, è possibile utilizzare OfType. In Cast, se l'elemento che stai elaborando non è il tipo desiderato, otterrai InvalidCastException. Con OfType, intercetterà il cast non valido e restituirà solo gli elementi che sono effettivamente il tipo che stai cercando.

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

Se si torna liste vuote però, ho il sospetto che i vostri tblStocks realtà non sta tornando JsonStocks e si sta tentando di proiettare qualche altro tipo (tblStock?) In un DTO (JsonStock). Se più tardi è il caso, è necessario utilizzare Seleziona per proiettare nel nuovo tipo dal tipo sottostante.

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>() esegue un cast.
  • (JsonStock) item esegue un cast o applica una conversione definita dall'utente.

Poiché tblStock è una classe LINQ to SQL e JsonStock è una classe personalizzata creata dall'utente, nessuno è un sottotipo dell'altro. Quindi, non puoi fare il cast tra i due.

Per risolvere questo problema, è possibile utilizzare la clausola Select di LINQ e convertire manualmente gli elementi:

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

operatori di conversione implicite ed esplicite sono ignored by Cast. Nel tuo caso ciò significa che

public static explicit operator JsonStock(tblStock stock) 

viene ignorato da Cast non sono però ignorati nel caso foreach

+0

Dice chi? Se ciò fosse vero, "Enumerable.Cast ()" non avrebbe alcun senso. http://msdn.microsoft.com/en-us/library/bb341406.aspx non contiene informazioni per supportare il reclamo. – VVS

+0

@VVS: non si capisce lo scopo di 'Enumerable.Cast ()'. L'input è enumerabile non generico. Il risultato è un enumerabile generico. L'intero scopo di questo metodo di estensione è quello di creare un enumerable tipizzato forte da un enumerable non generico che conosci il tipo di oggetti da. Vedi la mia risposta per maggiori dettagli. –

+0

@VVS Se si legge attentamente che il collegamento contiene effettivamente informazioni a supporto del reclamo come il link nella mia risposta. Il link che hai fornito parla degli operatori _cast_ come sopra è un operatore _conversion_. La sintassi per l'utilizzo di entrambi è la stessa (SomeType) ma non li rende uguali. Quindi non ho davvero il tuo downvote –

1

Ahhh, le meraviglie di overload dell'operatore espliciti.

Quindi, per risolvere il problema, è possibile chiamare prima una selezione.

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

Tuttavia direi che questo sovraccarico operatore è qualcosa che si dovrebbe sbarazzarsi di. Considerare la sostituzione con un costruttore di copia come l'implementazione

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

+1 Grazie per la soluzione: P – Jimbo