Tl; dr: вы всегда можете создать дешевую упаковку , что отлично и, вероятно, решит вашу проблему:IEnumerable<int> nums_enumerable = new[] { 1, 2, 3 }.AsEnumerable(); IQueryable<int> nums_queryable = nums_enumerable.AsQueryable();
IEnumerable
dynamic
Длинная версия заключается в том, что ваша проблема показывает, почему интерфейсы существуют в первую очередь: сообщить компилятору, что если реализовать два объекта IEnumerable
, то это контракт, с помощью которого они должны реализовать все методы в этом интерфейсе, и вызов этих методов выиграл «Ошибка во время выполнения.
То, что вы просите, - полностью игнорировать интерфейс, который называется утиным типом и на самом деле даже достижимо в C #, используя отражение или dynamic
ключевое слово DLR ( ключевое слово). Тем не менее, это действительно пахнет плохим дизайном, когда вам нужно использовать отражение, и вы вдруг потеряете все проверки времени и гарантии: ваш код, возможно, будет работать во время выполнения, может быть, нет. В этом случае это была бы плохая идея.
Примеры для утиного ввода обычно представляют собой простые варианты использования, но дело в том, что сигнатура метода еще должна соответствовать . В этом конкретном случае это еще хуже: разные методы в этом интерфейсе имеют одно и то же имя и, похоже, работают одинаково, они совершенно разные.
Сравните эти два случая, например:
-
В public static double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
случае, мы звоним IEnumerable.Average
. Параметр этого метода представляет собой анонимный метод , то есть метод в классе с генерируемым компилятором, который принимает параметр и возвращает значение, умноженное на 2. Метод фактически вызывает этот метод для каждого элемента в списке:double GetAverage(IEnumerable<int> items) { return items.Average(i => i * 2); }
IQueryable<T>
-
В public static double Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource,int>> selector)
случае, мы звоним 2
. Параметр этого метода представляет собой дерево выражений , то есть объект, содержащий информацию, которую мы хотим умножить на параметр 2
. Он буквально содержит двоичное выражение типа, Multiply
которое ссылается на два других выражения (a ParameterExpression
и a ConstantExpression
). Этот объект не выполняет никаких вычислений при передаче IQueryable.Average
:
double GetAverage(IQueryable<int> items)
{
return items.Average(i => i * 2);
}