C# 将表达式引用解析为实际值
我希望记录表达式中的实际值,而不是对表达式中使用的属性/字段/常量的引用。我这里有一把小提琴:它的代码(为子孙后代)是: 但我想看看这样的东西C# 将表达式引用解析为实际值,c#,.net,lambda,expression,C#,.net,Lambda,Expression,我希望记录表达式中的实际值,而不是对表达式中使用的属性/字段/常量的引用。我这里有一把小提琴:它的代码(为子孙后代)是: 但我想看看这样的东西 f => ((((f.Hue == Hues.Red) AndAlso (f.Shape == "Sphere")) AndAlso (f.Size == "Small")) AndAlso Not(f.IsDeleted)) 这是可以做到的,还是我遗漏了表达式的要点?所以需要的是去掉闭包。为此,需要重写表达式树(请注意,表达式访问者中并非考虑所
f => ((((f.Hue == Hues.Red) AndAlso (f.Shape == "Sphere")) AndAlso (f.Size == "Small")) AndAlso Not(f.IsDeleted))
这是可以做到的,还是我遗漏了表达式的要点?所以需要的是去掉闭包。为此,需要重写表达式树(请注意,表达式访问者中并非考虑所有情况):
您的表达式正在关闭
输入
。为什么不在中传递第二个Foo
并在表达式中使用它:expression
感谢@Sean的提示,但这个精心设计的示例最接近于读取的代码,在这里无法共享。它也不会“扩展”或“解决”对其价值观的引用。我认为这就是问题所在。涵盖所有案件是一项非常重要的任务。即使在这个简单的示例中,我们也遇到了问题:运行时异常(第1行):通过方法“closuresolver.VisitMember(System.Linq.Expressions.MemberExpression)”尝试访问字段“Program+c_uDisplayClass0_0.input”失败。
感谢您的反馈。我是针对.NET Core 3.1进行测试的-该示例在那里运行:我还能够在本地使用.NET Framework 4.7运行该示例,但在DotNetFiddle中没有-一定存在安全配置问题,无法执行该逻辑。请查找我在GitHub上启动的一个项目:现在该逻辑处理更多的情况,包括方法参数,索引器和静态字段/属性。NuGet软件包也可用。
f => ((((f.Hue == Hues.Red) AndAlso (f.Shape == value(Program+<>c__DisplayClass0_0).input.Shape)) AndAlso (f.Size == value(Program+<>c__DisplayClass0_0).input.SizeType.ToString())) AndAlso Not(f.IsDeleted))
f => ((((f.Hue == Hues.Red) AndAlso (f.Shape == "Sphere")) AndAlso (f.Size == "Small")) AndAlso Not(f.IsDeleted))
public static void Main()
{
// ...
var updated = (Expression<Func<Foo, bool>>)
new ClosureResolver().Visit(expression);
// Outputs:
// f => ((((f.Hue == Hues.Red) AndAlso (f.Shape == "Sphere")) AndAlso (f.Size == "Small")) AndAlso Not(f.IsDeleted))
Console.WriteLine(updated);
}
public class ClosureResolver : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Arguments.Count == 0)
{
var objExpr = Visit(node.Object);
if (objExpr is ConstantExpression objConstExpr)
{
var res = node.Method.Invoke(objConstExpr.Value, new object[0]);
return Expression.Constant(res);
}
}
return base.VisitMethodCall(node);
}
protected override Expression VisitMember(MemberExpression node)
{
var childExpr = Visit(node.Expression);
if (childExpr is ConstantExpression constExpr)
{
if (node.Member is FieldInfo field)
{
var constVal = field.GetValue(constExpr.Value);
return Expression.Constant(constVal);
}
else if (node.Member is PropertyInfo prop)
{
var constVal = prop.GetValue(constExpr.Value);
return Expression.Constant(constVal);
}
}
return base.VisitMember(node);
}
}
static void ClosureDemo()
{
var input = new Foo { Shape = "Sphere" };
Expression<Func<Foo, bool>> expr = f =>
f.Shape == input.Shape;
var updated = (Expression<Func<Foo, bool>>)
new ClosureResolver().Visit(expr);
var fn = expr.Compile();
var updatedFn = updated.Compile();
Console.WriteLine(fn(input)); // True
Console.WriteLine(updatedFn(input)); // True
input.Shape = "Cube";
Console.WriteLine(fn(input)); // True
Console.WriteLine(updatedFn(input)); // False
}