Я прочитал этот ответ и понял из него конкретный случай, который он выделяет, когда у вас есть лямбда внутри другой лямбды и вы не хотите, чтобы внутренняя лямбда также скомпилировалась с внешней. Когда внешний скомпилирован, вы хотите, чтобы внутреннее лямбда-выражение оставалось деревом выражений. Там да, имеет смысл цитировать внутреннее лямбда-выражение.
Но это все, я считаю. Есть ли другой вариант использования для цитирования лямбда-выражения?
А если нет, то почему все операторы LINQ, то есть расширения IQueryable<T>
, объявленные в классе Queryable
, цитируют предикаты или лямбда-выражения, которые они получают в качестве аргументов, когда они упаковывают эту информацию в класс MethodCallExpression
.
Я попробовал пример (и несколько других за последние пару дней), и в этом случае, похоже, нет смысла цитировать лямбду.
Вот выражение вызова метода для метода, который ожидает лямбда-выражение (а не экземпляр делегата) в качестве единственного параметра.
Затем я компилирую MethodCallExpression
, заключая его в лямбду.
Но это также не компилирует внутренний LambdaExpression
(аргумент метода GimmeExpression
). Он оставляет внутреннее лямбда-выражение в виде дерева выражений и не создает его экземпляр делегата.
На самом деле, он хорошо работает и без цитирования.
И если я цитирую аргумент, он ломается и выдает ошибку, указывающую на то, что я передаю неправильный тип аргумента методу GimmeExpression
.
В чем дело? К чему это цитирование?
private static void TestMethodCallCompilation()
{
var methodInfo = typeof(Program).GetMethod("GimmeExpression",
BindingFlags.NonPublic | BindingFlags.Static);
var lambdaExpression = Expression.Lambda<Func<bool>>(Expression.Constant(true));
var methodCallExpression = Expression.Call(null, methodInfo, lambdaExpression);
var wrapperLambda = Expression.Lambda(methodCallExpression);
wrapperLambda.Compile().DynamicInvoke();
}
private static void GimmeExpression(Expression<Func<bool>> exp)
{
Console.WriteLine(exp.GetType());
Console.WriteLine("Compiling and executing expression...");
Console.WriteLine(exp.Compile().Invoke());
}