Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting List<x> to List<y>

Tags:

c#

list

casting

The following code works:

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

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

So naturally you'd think that this code would work too:

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

But I get the error Invalid cast operation - does anybody know why that might happen?

UPDATE

tblStocks is a list of LINQ to SQL object, tblStock.
JsonStock is a simplified version of the tblStock class and gets returned to a webpage as a JSON object.

The following operator was built to do the 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;
    }
}
like image 425
Jimbo Avatar asked Sep 01 '11 11:09

Jimbo


3 Answers

Cast is used to change a non-generic collection into a generic one, i.e. it performs an unboxing operation. It can't be used the way you want.
When you have a look at the implementation of Cast and the CastIterator it uses, you see, that it takes an object and casts it to the specified type:

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

This only works if current really is a TResult. No custom conversions are applied in this case.
This is the default behavior, you can test it yourself:

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

What you want is best achieved with a simple Select if tblStocks is a generic enumerable:

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

Or, if tblStocks is a non-generic enumerable, you need to combine Cast and Select:

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

This will first unbox the objects in tblStocks to their real type (tblStock) and then cast it to the type you want (JsonStocks).

like image 125
Daniel Hilgarth Avatar answered Oct 20 '22 18:10

Daniel Hilgarth


implicit and explicit conversion operators are ignored by Cast. In your case that means that

 public static explicit operator JsonStock(tblStock stock)

is ignored by Cast they are however not ignored in the foreach case

like image 20
Rune FS Avatar answered Oct 20 '22 18:10

Rune FS


Instead of using Cast, consider using OfType. In Cast, if the item you are processing isn't the destired type, you will get the InvalidCastException. With OfType, it will trap for invalid cast and only return items that actually are the type that you are looking for.

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

If you return empty lists however, I would suspect that your tblStocks actually is not returning JsonStocks and you are trying to project some other type (tblStock?) into a DTO (JsonStock). If the later is the case, you need to use Select to project into the new type from the underlying type.

List<JsonStock> stock = repository.Single(id).tblStocks
                        .Select(stock => new JsonStock 
                             { 
                               Id = stock.Id,
                               Val1 = stock.Val1,
                               Val2 = stock.Val2,
                               ...
                             }
                         .ToList();
like image 23
Jim Wooley Avatar answered Oct 20 '22 17:10

Jim Wooley