Только быстро и коротко, на этот раз. Func<T,TResult>
является контравариантным (ИЗМЕНИТЬ : параметр типа T). Сейчас я работаю не с Func<T,TResult>
, а с Expression<Func<T,TResult>>
и, похоже, зашел в тупик. ОБНОВЛЕНИЕ – ПОЛНЫЙ ОБРАЗЕЦ КОДА:
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();
}
}
Вызов выполняется с использованием Expression<Func<IColoredObject, bool>>
в качестве аргумента и должен, если я правильно понял контравариантность, работать, потому что IColoredObject
является менее производным, чем Item
.
Я получаю исключение преобразования, говорящее что-то вроде
не может конвертировать
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]]
Есть ли способ исправить это и заставить его работать?
ИЗМЕНИТЬ:
Поскольку в том, что я сказал, есть некоторая неточность, вот еще предыстория. Образец кода обновлен. Кроме того, я проверил, что MSDN говорит о Func<T, TRes>
:
public Item GetFunc(Func<Item, bool> filter)
{
return Items.AsQueryable().Where(filter).FirstOrDefault();
}
Как указано MS, это можно использовать с контравариантным параметром типа, как указано ниже:
Func<IColoredObject, bool> filterFunc = x => x.Color == "black";
GetFunc(filterFunc);
Что снова заставляет меня задаться вопросом, почему это работает для Func<T, TRes>
, но не для Expression<Func<T, TRes>>
...
НАКОНЕЦ...
Проверенный ответ был выбран, потому что это то, что я в конечном итоге сделал. Как я сказал где-то в комментариях ниже, метод Get
использует NHibernate для получения данных. Но очевидно, что NHibernate имеет возможность принимать запросы через интерфейс и автоматически выбирать типы, реализующие интерфейс. Это не решает саму проблему, но, как вы можете прочитать ниже, реального решения нет, поскольку то, что здесь встречается, было ожидаемым поведением.
Func<T,TResult>
контравариантно, немного неправильно. Можно сказать, что он контравариантен по одному параметру своего типа (и ковариантен по другому). - person Damien_The_Unbeliever   schedule 12.07.2012