C# cast to interface with List and GroupBy
I'm a bit stumped about how to perform the necessary cast in the following:
public IList<IMyClass> Foo()
{
IList<IMyClass> foo = SomeQuery();
var result = foo.GroupBy(x => x.bar).Select(x => new MyClass()).ToList();
// So now I have a List<MyClass> which needs casting as IList<IMyClass&g开发者_如何学JAVAt;
return result;
}
using an explicit cast fails at run time. The error message isn't helpful but I'm guessing it maybe something to do with the GroupBy as I wouldn't normally expect to have any problem with something like this.
It's nothing to do with GroupBy
- it's because IList<T>
is invariant. If you could cast a List<MyClass>
to IList<IMyClass>
then the caller could then add an instance of a type which implemented IMyClass
but wasn't a MyClass
. (I usually think of this in terms of real world objects: a bunch of bananas isn't a fruit bowl: you can add an apple to a fruit bowl, but not to a bunch of bananas.)
The simplest way would be to manually specify the type in the Select clause:
public IList<IMyClass> Foo()
{
IList<IMyClass> foo = SomeQuery();
var result = foo.GroupBy(x => x.bar)
.Select<IGrouping<IMyClass, Bar>>, IMyClass>(x => new MyClass())
.ToList();
return result;
}
This means result
will actually be a List<IMyClass>
. I don't know the type of item within foo
which makes it tricky to give it in more detail - given your comment, I'll assume that that's IMyClass
, and that x.bar is of type Bar
.
Another alternative (which would be more useful if you wanted to use a query expression for the group/select part) would be to use Cast
:
public IList<IMyClass> Foo()
{
IList<IMyClass> foo = SomeQuery();
var result = foo.GroupBy(x => x.bar)
.Select(x => new MyClass())
.Cast<IMyClass>()
.ToList();
return result;
}
Or perform the cast within the Select lambda expression itself:
public IList<IMyClass> Foo()
{
IList<IMyClass> foo = SomeQuery();
var result = foo.GroupBy(x => x.bar)
.Select(x => (IMyClass) new MyClass())
.ToList();
return result;
}
EDIT: Apologies for the Select
failure. It's somewhat annoying that you have to specify both the source and the result, but there's no easy way of fixing that :( Given the ugliness involved, you may well be best off with Cast
.
Do you use .net 4?
then its easy. just return an IEnumerable of IMyClass. that supports covariance, and therefore you can cast it to base types.
otherwise. do this.
result.Select(i=> (IMyClass)i).ToList();
精彩评论