我正在尝试构建如下所示的动态表达式树:
Func<IEnumerable<int>, int, bool> dividesectionmethod = (x, y) =>
{
int nos1 = 0;
int nos2 = 0;
foreach (int i in x)
{
if (i <= y)
nos1++;
else
nos2++;
}
return nos1 > nos2;
};
为此我正在使用:
ParameterExpression enumerableExpression = Expression.Parameter(typeof(IEnumerable<int>), "x");
ParameterExpression intexpression = Expression.Parameter(typeof(int), "y");
ParameterExpression localvarnos1 = Expression.Variable(typeof(int), "nos1");
ParameterExpression localvarnos2 = Expression.Variable(typeof(int), "nos2");
ConstantExpression zeroConstantintval = Expression.Constant(0);
BinaryExpression bexplocalnos1 = Expression.Assign(localvarnos1, zeroConstantintval);
BinaryExpression bexplocalnos2 = Expression.Assign(localvarnos2, zeroConstantintval);
//As Expression does not support Foreach we need to get Enumerator before doing loop
ParameterExpression enumerator = Expression.Variable(typeof(IEnumerator<int>), "enumerator");
BinaryExpression assignenumerator = Expression.Assign(enumerator, Expression.Call(enumerableExpression, typeof(IEnumerable<int>).GetMethod("GetEnumerator")));
var currentelement = Expression.Parameter(typeof(int), "i");
var callCurrent = Expression.Assign(currentelement, Expression.Property(enumerator, "Current"));
BinaryExpression firstlessequalsecond = Expression.LessThanOrEqual(currentelement, intexpression);
MethodCallExpression movenext = Expression.Call(enumerator, typeof(IEnumerator).GetMethod("MoveNext"));
LabelTarget looplabel = Expression.Label("looplabel");
LabelTarget returnLabel = Expression.Label(typeof(bool), "retval");
BlockExpression block = Expression.Block(enumerableExpression, intexpression, localvarnos1, localvarnos2,
bexplocalnos1, bexplocalnos2, Expression.Loop(Expression.IfThenElse(
Expression.NotEqual(movenext, Expression.Constant(false)),
Expression.IfThenElse(firstlessequalsecond, Expression.Increment(localvarnos1), Expression.Increment(localvarnos2)),Expression.Break(looplabel)), looplabel),
Expression.Return(returnLabel, Expression.LessThan(localvarnos1, localvarnos2)));
Expression<Func<IEnumerable<int>, int, bool>> lambda = Expression.Lambda<Func<IEnumerable<int>, int, bool>>(block, Expression.Parameter(typeof(IEnumerable<int>), "x"),
Expression.Parameter(typeof(int), "y"));
Func<IEnumerable<int>, int, bool> mymethod = lambda.Compile();
但问题是 Expression.Lambda 抛出异常:
Expression of type 'System.Void' cannot be used for return type 'System.Boolean'
我不知道这个问题,因为我的 block 似乎没问题:
.Block() {
$x;
$y;
$nos1;
$nos2;
$nos1 = 0;
$nos2 = 0;
.Loop {
.If (.Call $enumerator.MoveNext() != False) {
.If ($i <= $y) {
.Increment($nos1)
} .Else {
.Increment($nos2)
}
} .Else {
.Break looplabel { }
}
}
.LabelTarget looplabel:;
.Return retval { $nos1 < $nos2 }
}
请让我知道可能是什么问题。
最佳答案
BlockExpression 的值只是 block 中最后一个表达式的值。不要包含 ReturnExpression,只需让最后一个表达式成为您要返回的值即可。
此外,您需要将 block 的 ParameterExpressions 声明为 Expression.Block 方法的单独参数。您已将它们包含在表达式列表中,这将导致它们被评估为表达式但不会在 block 中声明它们。
此外,Expression.Increment “不会更改传递给它的对象的值”,因此您需要将增量表达式包装在赋值表达式中。
BlockExpression block = Expression.Block(
new ParameterExpression[] {
localvarnos1, localvarnos2, enumerator, currentelement },
bexplocalnos1,
bexplocalnos2,
assignenumerator,
Expression.Loop(
Expression.IfThenElse(
Expression.NotEqual(movenext, Expression.Constant(false)),
Expression.Block(
callCurrent,
Expression.IfThenElse(
firstlessequalsecond,
Expression.Assign(
localvarnos1,
Expression.Increment(localvarnos1)),
Expression.Assign(
localvarnos2,
Expression.Increment(localvarnos2)))),
Expression.Break(looplabel)),
looplabel),
Expression.LessThan(localvarnos1, localvarnos2));
Expression<Func<IEnumerable<int>, int, bool>> lambda =
Expression.Lambda<Func<IEnumerable<int>, int, bool>>(
block,
enumerableExpression,
intexpression);
关于c# - 构建动态表达式树时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3646283/