变量''类型''引用范围'',但它没有定义

Han*_*ans 27 c# expression-trees

那么,以下代码是自我解释的; 我想将两个表达式合并为一个使用And运算符.最后一行导致符文时间错误:

附加信息:从范围''引用的'System.String'类型的变量'y',但未定义

码:

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
Run Code Online (Sandbox Code Playgroud)

das*_*ght 18

问题是参数表达式对象表示y表达式中的变量e1并且e2是不同的.这两个变量被命名为相同且具有相同类型的事实并不重要:e1.Parameters.First()并且它们e2.Parameters.First()不是同一个对象.

这会导致您看到的问题:只有e1参数y可用Lambda<>,而e2参数y超出范围.

要解决此问题,请使用ExpressionAPI创建e1e2.这样您就可以在它们之间共享参数表达式,从而消除了范围问题.

  • 没有代码,这不是一个好的答案 (7认同)
  • 我应该使用什么样的API,你能帮忙吗? (2认同)

Cod*_*ter 13

如另一个答案中所示,您有两个表达式,其中两个都有一个名为的参数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");
Run Code Online (Sandbox Code Playgroud)

当然,您需要一个只用一个参数组合两个表达式的表达式.您可以像这样重建表达式:

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");
Run Code Online (Sandbox Code Playgroud)

至于你的意见,你不希望重建的表达,但这样做在现有的表达的身体和参数:该作品使用ExpressionRewriter结合在C#两个lambda表达式,并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");
Run Code Online (Sandbox Code Playgroud)


Han*_*ans 12

谢谢大家的合作.

由于@dasblinkenlight指出两个表达式中的两个参数不一样.原因?好吧,这是编译技巧.在编译时,它为每个表达式创建一个类,并将每个参数命名为xxx1,xxx2,......与原始名称完全不同.

和.Net 4.0+的答案:

如何结合两个lambda

  • 希望我对此有一个以上的支持。 (2认同)