C# 在父表达式中重用表达式结果
假设我有一个结合了两个子C# 在父表达式中重用表达式结果,c#,expression-trees,C#,Expression Trees,假设我有一个结合了两个子表达式(所有表达式将返回一个int)的函数,根据规则“ab+a”: 如果我编译并运行结果的表达式,编译器是否足够聪明,知道参数a不需要在内部显式计算两次?a和b的表达式树可能非常冗长且昂贵 事实上,如果生成的表达式将对a求值两次,那么缓存该值以供重用的最佳方法是什么 例如,我想知道这是否可行(但我不清楚ConstantExpression是否可以保存运行时确定的表达式结果): 注意:我知道这可能会被重构为“a(b+1)”,但我最初的问题成立,因为我有其他组合,它们可能会以
表达式
(所有表达式
将返回一个int
)的函数,根据规则“ab+a”:
如果我编译并运行结果的表达式
,编译器是否足够聪明,知道参数a
不需要在内部显式计算两次?a
和b
的表达式
树可能非常冗长且昂贵
事实上,如果生成的表达式
将对a
求值两次,那么缓存该值以供重用的最佳方法是什么
例如,我想知道这是否可行(但我不清楚ConstantExpression
是否可以保存运行时确定的表达式结果):
注意:我知道这可能会被重构为“a(b+1)”,但我最初的问题成立,因为我有其他组合,它们可能会以类似的方式多次重用a
或b
。例如,“a2+ab+b2”。是的,对于原始表达式,它将被计算两次,但您可以缓存它<代码>表达式。常量在这种情况下不起作用,因为它需要常量值,并且需要在表达式执行期间对其求值,但您可以使用Expression.Variable
声明新变量,然后使用Expression.Assign
将值保存到该变量,然后使用这些表达式声明Expression.Block
,因为变量
需要自己的块。
如果需要,可以对b
变量执行相同的操作
以下代码将生成此类表达式:
(obj) => { int cached = obj.A; return cached*obj.B + cached; }
以下是示例代码:
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main(string[] args)
{
ParameterExpression param = Expression.Parameter(typeof(Test), "obj");
Expression a = Expression.Property(param, "A");
Expression b = Expression.Property(param, "B");
Expression result = CustomCombine(a, b);
var lambda = Expression.Lambda<Func<Test, int>>(result, new ParameterExpression[] { param });
Func<Test, int> func = lambda.Compile();
var obj = new Test();
var val = func(obj);
Console.WriteLine("Result is " + val);
}
private static Expression CustomCombine(Expression a, Expression b)
{
var variable = Expression.Variable(a.Type, "cached");
var aVal = Expression.Assign(variable, a);
var mult = Expression.Multiply(variable, b);
var result = Expression.Add(mult, variable);
// here we are making Block with variable declaration and assigment
var block = Expression.Block(new ParameterExpression[]{variable}, aVal, result);
return block;
}
}
public class Test
{
public int A
{
get
{
Console.WriteLine("Property A is accessed");
return 42;
}
}
public int B
{
get
{
return 1;
}
}
}
使用系统;
使用System.Linq.Expressions;
公共课程
{
公共静态void Main(字符串[]args)
{
ParameterExpression param=表达式参数(typeof(Test),“obj”);
表达式a=表达式属性(参数“a”);
表达式b=表达式属性(参数“b”);
表达式结果=自定义组合(a,b);
var lambda=Expression.lambda(结果,新参数Expression[]{param});
Func Func=lambda.Compile();
var obj=新测试();
var val=func(obj);
Console.WriteLine(“结果为”+val);
}
私有静态表达式CustomCombine(表达式a、表达式b)
{
var variable=Expression.variable(a.Type,“cached”);
var aVal=表达式.Assign(变量,a);
var mult=表达式。乘法(变量,b);
var result=Expression.Add(mult,variable);
//这里我们用变量声明和赋值来生成块
var block=Expression.block(新参数Expression[]{variable},aVal,result);
返回块;
}
}
公开课考试
{
公共INTA
{
得到
{
Console.WriteLine(“访问了属性A”);
返回42;
}
}
公共int B
{
得到
{
返回1;
}
}
}
还有工作。NetFiddle示例-谢谢,这正是我想要的。
(obj) => { int cached = obj.A; return cached*obj.B + cached; }
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main(string[] args)
{
ParameterExpression param = Expression.Parameter(typeof(Test), "obj");
Expression a = Expression.Property(param, "A");
Expression b = Expression.Property(param, "B");
Expression result = CustomCombine(a, b);
var lambda = Expression.Lambda<Func<Test, int>>(result, new ParameterExpression[] { param });
Func<Test, int> func = lambda.Compile();
var obj = new Test();
var val = func(obj);
Console.WriteLine("Result is " + val);
}
private static Expression CustomCombine(Expression a, Expression b)
{
var variable = Expression.Variable(a.Type, "cached");
var aVal = Expression.Assign(variable, a);
var mult = Expression.Multiply(variable, b);
var result = Expression.Add(mult, variable);
// here we are making Block with variable declaration and assigment
var block = Expression.Block(new ParameterExpression[]{variable}, aVal, result);
return block;
}
}
public class Test
{
public int A
{
get
{
Console.WriteLine("Property A is accessed");
return 42;
}
}
public int B
{
get
{
return 1;
}
}
}