Just a quick and short one, this time. Func<T,TResult>
is contravariant (EDIT : The Type Parameter T is). Now, I don't work with Func<T,TResult>
, but rather with Expression<Func<T,TResult>>
, and seem to have reached a dead end. UPDATE - FULL CODE SAMPLE :
public interface IColoredObject
{
string Color { get; }
}
public class Item : IColoredObject
{
public string Color { get; set; }
public double Price { get; set; }
}
public partial class MainWindow : Window
{
private IList<Item> _items;
public IList<Item> Items
{
get
{
if (_items == null)
{
_items = new List<Item>();
_items.Add(new Item() { Color = "black" });
_items.Add(new Item() { Color = "blue" });
_items.Add(new Item() { Color = "red" });
}
return _items;
}
}
public MainWindow()
{
InitializeComponent();
Expression<Func<IColoredObject, bool>> filter = x => x.Color == "black";
Item i = Get(filter);
}
public Item Get(Expression<Func<Item, bool>> filter)
{
return Items.AsQueryable().Where(filter).FirstOrDefault();
}
}
The call is made using an Expression<Func<IColoredObject, bool>>
as argument and should, if I haven't misunderstood contravariance, work, because IColoredObject
is less derived that Item
.
What I get is a conversion Exception saying something like
cannot convert
System.Linq.Expressions.Expression`1[System.Func`2[MyNs.IColoredObject,System.Boolean]]
To
System.Linq.Expressions.Expression`1[System.Func`2[MyNs.Item,System.Boolean]]
Is there any way of fixing this and getting it to work?
EDIT:
Since there's some inaccuracy in what I've said, here's more background. Code sample updated. Furthermore, I checked what MSDN said about Func<T, TRes>
:
public Item GetFunc(Func<Item, bool> filter)
{
return Items.AsQueryable().Where(filter).FirstOrDefault();
}
As indicated by MS, this can be used with a contravariant Type param, as listed below:
Func<IColoredObject, bool> filterFunc = x => x.Color == "black";
GetFunc(filterFunc);
Which again makes me wonder why this works for Func<T, TRes>
but not for Expression<Func<T, TRes>>
...
FINALLY...
The checked answer was selected because it is what I eventually did. As I said somewhere in the comments below, the Get
-Method utilizes NHibernate to fetch data. But obviously NHibernate has a feature of accepting queries over an interface and auto-selecting the types that implement the interface. This does not solve the issue itself, but as you can read below, there is not real solution, since what encountered here was expected behaviour.