为什么不同版本的 .net(或编译器)会为相同的表达式生成不同的表达式树
Why do different versions of .net (or the compiler) generate different expression trees for the same expression
在我的一个库中,我有代码 returns 来自表达式的 MethodInfo:
public MethodInfo GetMethod(Expression expression)
{
var lambdaExpression = (LambdaExpression)expression;
var unaryExpression = (UnaryExpression)lambdaExpression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
return (MethodInfo)methodInfoExpression.Value;
}
我有一系列辅助函数来启用如下调用:
public MethodInfo Func<T, R, A1>(Expression<Func<T, Func<A1, R>>> expression)
{
return GetMethod(expression);
}
这将启用以下语法:
var methodInfo = Func<TestClass, bool, string>(x => x.AnInstanceMethodThatTakesAStringAndReturnsABool);
效果很好,直到我最近将库升级到 .Net 4.6.1 和最新的 c# 编译器。
在以前的 .net 版本中,表达式的形式为:
{x => Convert(CreateDelegate(System.Func`2[System.String, System.Boolean], x, Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String)))}
因此我的代码会寻找 methodInfoExpression 作为 methodCallExpression 的最后一个参数。
现在,在 .Net 4.6.1(最新的 c# 编译器)中,编译器似乎生成了不同形式的表达式:
{x => Convert(Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String).CreateDelegate(System.Func`2[System.String, System.Boolean], x))}
我当前的代码中断,因为最后一个参数不是 ConstantExpression。看着它-容易修复,只需更改为
var methodInfoExpression = (ConstantExpression)methodCallExpression.Object;
显然,GetMethod 函数非常脆弱,并且会随着编译器生成表达式的方式发生变化。我很好奇更改的原因以及如何重构 GetMethod 以使其对编译器生成的表达式树更具弹性。
I'm curious as to the reason for the change
从 .NET 4.5 开始,有两种方法可以从 MethodInfo
中创建委托:
MethodInfo
和 上的实例方法
Delegate.CreateDelegate
静态方法
看起来 Microsoft 决定从使用 #2 切换到使用 #1,无论出于何种原因(它可能更有效)。
how I might refactor GetMethod
so that it is more resilient to the expression tree generated by the compiler?
您可以使用 expression tree visitor,并以这种方式查找方法信息。
在我的一个库中,我有代码 returns 来自表达式的 MethodInfo:
public MethodInfo GetMethod(Expression expression)
{
var lambdaExpression = (LambdaExpression)expression;
var unaryExpression = (UnaryExpression)lambdaExpression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
return (MethodInfo)methodInfoExpression.Value;
}
我有一系列辅助函数来启用如下调用:
public MethodInfo Func<T, R, A1>(Expression<Func<T, Func<A1, R>>> expression)
{
return GetMethod(expression);
}
这将启用以下语法:
var methodInfo = Func<TestClass, bool, string>(x => x.AnInstanceMethodThatTakesAStringAndReturnsABool);
效果很好,直到我最近将库升级到 .Net 4.6.1 和最新的 c# 编译器。
在以前的 .net 版本中,表达式的形式为:
{x => Convert(CreateDelegate(System.Func`2[System.String, System.Boolean], x, Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String)))}
因此我的代码会寻找 methodInfoExpression 作为 methodCallExpression 的最后一个参数。
现在,在 .Net 4.6.1(最新的 c# 编译器)中,编译器似乎生成了不同形式的表达式:
{x => Convert(Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String).CreateDelegate(System.Func`2[System.String, System.Boolean], x))}
我当前的代码中断,因为最后一个参数不是 ConstantExpression。看着它-容易修复,只需更改为
var methodInfoExpression = (ConstantExpression)methodCallExpression.Object;
显然,GetMethod 函数非常脆弱,并且会随着编译器生成表达式的方式发生变化。我很好奇更改的原因以及如何重构 GetMethod 以使其对编译器生成的表达式树更具弹性。
I'm curious as to the reason for the change
从 .NET 4.5 开始,有两种方法可以从 MethodInfo
中创建委托:
MethodInfo
和 上的实例方法
Delegate.CreateDelegate
静态方法
看起来 Microsoft 决定从使用 #2 切换到使用 #1,无论出于何种原因(它可能更有效)。
how I might refactor
GetMethod
so that it is more resilient to the expression tree generated by the compiler?
您可以使用 expression tree visitor,并以这种方式查找方法信息。