Reputation: 4137
In the code below, note that Bar derives from Foo.
class Program
{
public class Foo
{
public string data { get; set; }
}
public class Bar : Foo
{
}
static void Main(string[] args)
{
var bars = new List<Bar>();
bars.Add(new Bar() { data = "hello" });
bars.Add(new Bar() { data = "world" });
var resultsA = GetFoos(bars, (b => b.data.StartsWith("h")));
var resultsB = GetBars(bars, (b => b.data.StartsWith("h")));
}
static List<Foo> GetFoos(List<Foo> fooList, Func<Foo, bool> criteria)
{
return fooList.Where(criteria).ToList();
}
static List<Bar> GetBars(List<Bar> barList, Func<Bar, bool> criteria)
{
return barList.Where(criteria).ToList();
}
}
The GetFoos method call results in this compiler error message:
Argument 1: cannot convert from 'System.Collections.Generic.List<Program.Bar>
' to 'System.Collections.Generic.List<Program.Foo>
'
However, when that line is commented out, the call to GetBars() executes correctly.
Is what I'm trying to accomplish here, a query against a common ancestor class, possible with linq?
Upvotes: 3
Views: 90
Reputation: 5445
Update the List
to IEnumerable
:
static IEnumerable<Foo> GetFoos(IEnumerable<Foo> fooList, Func<Foo, bool> criteria)
{
return fooList.Where(criteria).ToList();
}
static IEnumerable<Bar> GetBars(IEnumerable<Bar> barList, Func<Bar, bool> criteria)
{
return barList.Where(criteria).ToList();
}
This is because IEnumerable<Bar>
is a subtype of IEnumerable<Foo>
. The subtyping is preserved because IEnumerable<T>
is covariant on T
.
Neither IList<Boo>
nor IList<Foo>
is a subtype of the other, because IList<T>
is invariant on T
.
Upvotes: 4
Reputation: 61369
Only interfaces can be covariant. Since you are trying to assign a List<Derived>
to a List<Base>
, you need to use a covariant interface instead. IEnumerable
is already covariant, so just change your code to:
static List<Foo> GetFoos(IEnumerable<Foo> fooList, Func<Foo, bool> criteria)
{
return fooList.Where(criteria).ToList();
}
static List<Bar> GetBars(IEnumerable<Bar> barList, Func<Bar, bool> criteria)
{
return barList.Where(criteria).ToList();
}
Proof on IdeOne
Upvotes: 6