Reputation: 7307
I have an abstract class called Grouping. I have a subclass called GroupingNNA.
public class GroupingNNA : Grouping {
// blah blah blah
}
I have a List that contains items of type GroupingNNA, but is actually declared to contain items of type Grouping.
List<Grouping> lstGroupings = new List<Grouping>();
lstGroupings.Add(
new GroupingNNA { fName = "Joe" });
lstGroupings.Add(
new GroupingNNA { fName = "Jane" });
The Problem: The following LINQ query blows up on me because of the fact that lstGroupings is declared as List< Grouping> and fName is a property of GroupingNNA, not Grouping.
var results = from g in lstGroupings
where r.fName == "Jane"
select r;
Oh, and this is a compiler error, not a runtime error. Thanks in advance for any help on this one!
More Info: Here is the actual method that won't compile. The OfType() fixed the LINQ query, but the compiler doesn't like the fact that I'm trying to return the anonymous type as a List< Grouping>.
private List<Grouping> ApplyFilterSens(List<Grouping> lstGroupings, string fSens) {
// This works now! Thanks @Lasse
var filtered = from r in lstGroupings.OfType<GroupingNNA>()
where r.QASensitivity == fSens
select r;
if (filtered != null) {
**// Compiler doesn't like this now**
return filtered.ToList<Grouping>();
}
else
return new List<Grouping>();
}
Upvotes: 7
Views: 241
Reputation: 144112
Calling ToList<AnotherType>()
is putting yourself back in the same boat as before - generic covariance/contravarience is not supported - e.g. List<Type>
is not compatible with or convertible to/from List<SubType>
.
You need to use filtered.OfType<Grouping>().ToList();
- the first gets you back to an IEnumerable<Grouping>
instead of an IEnumerable<GroupingNNA>
, and then ToList
just converts the IEnumerable
to a List
of the same generic type.
Upvotes: 5
Reputation: 391276
Try:
= from g in lstGroupings.OfType<GroupingNNA>()
this will skip any elements not of type GroupingNNA
, and also make the compiler use GroupingNNA
as the type for g
.
In response to comment and edited question. No, the compiler will certainly not be happy about your changed collection, but you can fix that:
return new List<Grouping>(filtered.ToArray());
This relies on the fact that arrays in .NET are co/contra-variant, which allows the compiler to treat GroupingNNA[]
as Grouping[]
for the constructor.
Also, you don't need the if (filtered != null)
check, you will get a collection in filtered
, it might just not produce any elements, but filtered
will always be non-null
.
This means your code can be written as:
var filtered = from r in lstGroupings.OfType<GroupingNNA>()
where r.QASensitivity == fSens
select r;
return new List<Grouping>(filtered.ToArray());
or even just:
return new List<Grouping>((from r in lstGroupings.OfType<GroupingNNA>()
where r.QASensitivity == fSens
select r).ToArray());
or even shorter if you drop the linq syntax:
return new List<Grouping>((lstGroupings.OfType<GroupingNNA>()
.Where(r => r.QASensitivity == fSens).ToArray());
Note that you can of course use OfType
to go the other way as well:
return filtered.OfType<Grouping>().ToList();
there shouldn't be any big performance differences between the different ways here, if in doubt, measure it, but I would go with what you find easiest to read and understand.
Upvotes: 6