Casting List<x> to List<y>
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 w开发者_JS百科ould 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;
}
}
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
).
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
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();
Ahhh, the wonders of explicit operator overloads.
So to fix your problem you might want to call a Select beforehand.
List<JsonStock> stock = repository.Single(id).tblStocks.Select(x => (JsonStock)x).ToList()
However i'd say that this operator overload is something you should get rid of. Consider replacing it with a copy constructor like implementation
class JsonStock
{
public JsonStock(tblStock other)
{
// copy values here
}
}
tblStocks.Cast<JsonStock>()
performs a cast.(JsonStock) item
performs a cast or applies a custom-defined conversion.
Since tblStock is a LINQ to SQL class and JsonStock is a custom class created by you, none is a subtype of the other. Thus, you cannot cast between the two.
To fix this, you can use the Select
clause of LINQ and manually convert the elements:
List<JsonStock> stock = repository.Single(id).tblStocks
.Select(item => (JsonStock) item).ToList();
精彩评论