c# - create - variable '''' de tipo '''' referenciada desde el alcance '''', pero no está definida
lambda c# (3)
Como se indica en la otra respuesta, tiene dos expresiones donde ambas tienen un parámetro llamado y
. Los que no se relacionan automáticamente entre sí.
Para compilar correctamente su expresión, debe especificar los parámetros de ambas expresiones de origen:
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");
Por supuesto, querrá una expresión que combine ambas expresiones con un solo parámetro. Puedes reconstruir las expresiones así:
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");
En cuanto a su comentario, no desea reconstruir la expresión, sino hacerlo en el cuerpo y los parámetros de una expresión existente: esto funciona usando ExpressionRewriter
de Combinar dos expresiones lambda en c # y AndAlso
de Reemplazar el nombre del parámetro en el Cuerpo de una Expresión :
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");
Bueno, el siguiente código es autoexplicativo; Quiero combinar dos expresiones en una utilizando el operador And
. La última línea causa un error en el tiempo de ejecución:
Información adicional: variable ''y'' de tipo ''System.String'' referenciada desde el alcance '''', pero no está definida
Código:
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
El problema es que los objetos de expresión de parámetros que representan la variable y
en las expresiones e1
y e2
son diferentes. El hecho de que las dos variables tengan el mismo nombre y el mismo tipo no importa: e1.Parameters.First()
y e2.Parameters.First()
no es el mismo objeto.
Esto causa el problema que ve: solo el parámetro e1
de e1
está disponible para Lambda<>
, mientras que el parámetro e2
de e2
está fuera de alcance.
Para solucionar este problema, use las API de Expression
para crear e1
y e2
. De esta manera usted podría compartir la expresión de parámetros a través de ellos, eliminando así el problema de alcance.
Gracias a todos colaboraron.
Como ha señalado dasblinkenlight , los dos parámetros en las dos expresiones no son los mismos. ¿Razón? Bueno, es el truco del compilador. Al compilar, crea una clase para cada expresión y nombra cada parámetro algo así como xxx1, xxx2, ... completamente diferente de los nombres originales.
Y la respuesta para .Net 4.0+: