gpt4 book ai didi

c# - Expression.Block() 可以在 lambda 闭包中返回一个值吗?

转载 作者:行者123 更新时间:2023-11-30 16:44:11 24 4
gpt4 key购买 nike

我想将两个单独的表达式树编译成一个编译的 lambda。我有一个 double[] 输入数组。第一个表达式树(为简单起见,我们称之为 ExpressionA)创建一个新的相同长度的 double[] 数组,其中包含转换的结果输入数组值。第二个表达式树 (ExpressionB) 对转换后的数组进行一些计算并返回单个 double 输出,我想返回它。

我认为以下方法可行,但我遇到了问题:

ParameterExpression inputArray = Expression.Parameter(typeof(double[]));
ParameterExpression xformArray = Expression.Parameter(typeof(double[]));

Func<double[], double> compiled = Expression.Lambda<Func<double[], double>>(
Expression.Block(new ParameterExpression[] { inputArray, xformArray },
Expression.Assign(xformArray, ExpressionA(inputArray)),
ExpressionB(xformArray)),
inputArray).Compile();

尽管程序已构建,但在我调用已编译函数时出现 NullReference 运行时异常(堆栈跟踪没有帮助,因为它没有进入 lambda_method())。

然而,这个更简单的版本运行得很好(只是传入 xformed 数组):

Func<double[], double> compiled = Expression.Lambda<Func<double[], double>>(
ExpressionB(xformArray)), xformArray).Compile();

但是这个更简单的版本也因 NullReference 异常而失败:

Func<double[], double> compiled = Expression.Lambda<Func<double[], double>>(
Expression.Block(new ParameterExpression[] { xformArray },
ExpressionB(xformArray)),
xformArray).Compile();

最后,我还尝试了这个概念验证版本,它也有效(让我相信 Block 在概念上应该可以在 lambda 中使用):

Func<double[], double> compiled = Expression.Lambda<Func<double[], double>>(
Expression.Block(new ParameterExpression[] { inputArray, xformArray },
Expression.Constant(0.0)), // stub test
inputArray).Compile();

所以我的问题是如何在单个编译的 lambda 中按顺序使用两个表达式树?

最佳答案

没有好的Minimal, Complete, and Verifiable code example ,尤其是没有具体说明什么是 ExpressionA()ExpressionB() 以及您实际如何使用它们,就不可能确定最佳答案可能是什么.但是,我看到的最明显的问题是您正在重新声明 inputArray,这会在 block 中创建一个新的局部变量。由于没有赋值给任何东西,它的值当然是 null

修复方法是将它从 block 的变量中删除,只留下 xformArray:

Func<double[], double> compiled = Expression.Lambda<Func<double[], double>>(
Expression.Block(new ParameterExpression[] { xformArray },
Expression.Assign(xformArray, ExpressionA(inputArray)),
ExpressionB(xformArray)),
inputArray).Compile();

同样,如果没有良好的 MCVE,就不可能确定您的选择是什么。但是恕我直言,用代码表达表达式总是比手动构建它们更可取。例如:

Func<double[], double> MakeExpression(
Func<double[], double[]> transformA,
Func<double[], double> transformB)
{
return a => transformB(transformA(a));
}

如果出于某种原因需要将转换本身表示为表达式,您仍然可以在构建其余的 lambda 之前单独编译它们:

Func<double[], double> MakeExpression(
Expression<Func<double[], double[]>> transformA,
Expression<Func<double[], double>> transformB)
{
Func<double[], double[]> transformACompiled = transformA.Compile();
Func<double[], double> transformBCompiled = transformB.Compile();

return a => transformBCompiled(transformACompiled(a));
}

但是,如果您必须显式地使用 Expression 类来完成整个操作,则上面第一个代码示例中的更正应该可以解决您的问题。

最后,我要指出您的原始代码可以大大简化:

    Func<double[], double> compiled = Expression.Lambda<Func<double[], double>>(
ExpressionB(ExpressionA(inputArray)),
inputArray).Compile();

当然,在您的真实代码中,您可能会有更复杂的表达式。但至少对于您帖子中的示例,您甚至不需要 block 或中间局部变量。

关于c# - Expression.Block() 可以在 lambda 闭包中返回一个值吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43858048/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com