Переменная '' типа '', ссылающаяся на область видимости '', но не определена
Ну, следующий код самообучающийся; Я хочу объединить два выражения в один, используя оператор And
. Последняя строка вызывает ошибку rune-time:
Дополнительная информация: переменная 'y' типа 'System.String', ссылающаяся на область действия '', но не определена
код:
Expression<Func<string, bool>> e1 = y => y.Length < 100;
Expression<Func<string, bool>> e2 = y => y.Length < 200;
var e3 = Expression.And(e1.Body, e2.Body);
var e4 = Expression.Lambda<Func<string, bool>>(e3, e1.Parameters.ToArray());
e4.Compile(); // <--- causes run-time error
Ответы
Ответ 1
Спасибо всем, кто сотрудничал.
Как указывал dasblinkenlight, два параметра в двух выражениях не совпадают. Причина? Ну, это трюк компилятора. При компиляции он создает класс для каждого выражения и называет каждый параметр, похожий на xxx1, xxx2,... полностью отличный от исходных имен.
И ответ для .Net 4.0 +:
Как объединить два лямбда
Ответ 2
Проблема заключается в том, что объекты выражения параметров, которые представляют переменную y
в выражениях e1
и e2
, различны. Тот факт, что две переменные называются одинаковыми и имеют один и тот же тип, не имеет значения: e1.Parameters.First()
и e2.Parameters.First()
- не тот же объект.
Это вызывает проблему: параметр e1
y
доступен для Lambda<>
, а параметр e2
y
недоступен.
Чтобы устранить эту проблему, используйте API Expression
для создания e1
и e2
. Таким образом, вы сможете совместно использовать выражение параметров по ним, тем самым устраняя проблему области.
Ответ 3
Как указано в другом ответе, у вас есть два выражения, в которых оба параметра имеют параметр y
. Они не связаны автоматически друг с другом.
Чтобы правильно скомпилировать ваше выражение, вам нужно указать оба параметра исходного выражения:
Expression<Func<string, bool>> e1 = (y => y.Length > 0);
Expression<Func<string, bool>> e2 = (y => y.Length < 5);
var e3 = Expression.And(e1.Body, e2.Body);
// (string, string) by adding both expressions' parameters.
var e4 = Expression.Lambda<Func<string, string, bool>>(e3, new[]
{
e1.Parameters[0],
e2.Parameters[0]
});
Func<string, string, bool> compiledExpression = e4.Compile();
bool result = compiledExpression("Foo", "Foo");
Конечно, вам нужно выражение, которое объединяет оба выражения только с одним параметром. Вы можете перестроить выражения следующим образом:
ParameterExpression param = Expression.Parameter(typeof(string), "y");
var lengthPropertyExpression = Expression.Property(param, "Length");
var e1 = Expression.GreaterThan(lengthPropertyExpression, Expression.Constant(0));
var e2 = Expression.LessThan(lengthPropertyExpression, Expression.Constant(5));
var e3 = Expression.AndAlso(e1, e2);
var e4 = Expression.Lambda<Func<string, bool>>(e3, new[] { param });
Func<string, bool> compiledExpression = e4.Compile();
bool result = compiledExpression("Foo");
Что касается вашего комментария, что вы не хотите перестраивать выражение, но делаете это на существующей структуре выражения и параметрах: это работает с использованием ExpressionRewriter
из Сочетание двух лямбда-выражений в С# и AndAlso
из Замена имени параметра в кубе выражения:
Expression<Func<string, bool>> e1 = (y => y.Length > 0);
Expression<Func<string, bool>> e2 = (z => z.Length < 10);
var e3 = ParameterReplacer.AndAlso<string>(e1, e2);
Func<string, bool> compiledExpression = e3.Compile();
bool result = compiledExpression("Foo");