开发者

Casting the results of linq-to-sql

Working with interfaces, we commonly have a var or an IQueryable that is going to return a set of data objects that we will then cast to the interface and return as a List or IList, like this:

var items =
from t in SomeTable
where t.condition == true
select;
return items.ToList( ).Cast<SomeInterface>( ).ToList( );

NOTE: items.Cast( ).ToList( ) will compile, but will throw an InvalidCastException at run time.

Is there a better way? (I put the ToList/Cast/ToList in an extension method, but that's not really any better...)

return items.CastToList<SomeCl开发者_运维百科ass, SomeInterface>( );

Thanks!


What you're doing is correct (you can't call Cast directly on the IQueryable), but it's sub-optimal, because you're creating 2 lists when you really only need one. Use AsEnumerable instead of the first ToList :

return items.AsEnumerable().Cast<SomeInterface>().ToList();

Calling AsEnumerable will cause Cast to be evaluated on a IEnumerable, not IQueryable, so the cast will be done on the actual object returned from the DB, rather than directly in the DB.


What's the point of the first ToList() call? Why not just items.Cast<SomeInterface>().ToList()?

Alternately, you could do this instead:

var items = from t in SomeTable
            where t.condition == true
            select (SomeInterface) t;
return items.ToList();

If t doesn't implement SomeInterface it will still fail at runtime, though.

This will do the same thing, but won't fail; rather it will give you null if the object doesn't implement the interface:

var items = from t in SomeTable
            where t.condition == true
            select t as SomeInterface;
return items.ToList();


A few solutions...

Instead of converting data after collecting it, you could consider make a projection while collecting it.

return items.Select(x=>x as SomeInterface).ToList();

If you do this frequently, an extension method may still be helpful. It doesn't have to be Tolist/Cast/ToList as you mentioned though. Cast will take an IEnumerable already, but you can create an overload that accepts an IQueryable, something like this (untested).

public IEnumerable<TResult> Cast<T, TResult>(this IQueryable<T> input)
{
    return input.AsEnumerable().Cast<TResult>();
}

This would whittle your code down to this:

return items.Cast<SomeClass, SomeInterface>.ToList();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜