Why do different versions of .net (or the compiler) generate different expression trees for the same expression

In one of my libraries, I have code that returns MethodInfo from an expression:

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; } 

I had a series of helper functions to enable calls such as:

 public MethodInfo Func<T, R, A1>(Expression<Func<T, Func<A1, R>>> expression) { return GetMethod(expression); } 

This will enable the following syntax:

 var methodInfo = Func<TestClass, bool, string>(x => x.AnInstanceMethodThatTakesAStringAndReturnsABool); 

This worked fine until I recently upgraded the library to .Net 4.6.1 and the latest C # compiler.

In the previous version of .net, the expression will look like:

 {x => Convert(CreateDelegate(System.Func`2[System.String, System.Boolean], x, Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String)))} 

Therefore, my code will look for methodInfoExpression as the last argument to the CallExpression method.

Now, in .Net 4.6.1 (the latest C # compiler), the compiler seems to produce a different form of expression:

 {x => Convert(Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String).CreateDelegate(System.Func`2[System.String, System.Boolean], x))} 

My current code breaks because the last argument is not a constant expression. Looking at it is easy to fix, just change to

  var methodInfoExpression = (ConstantExpression)methodCallExpression.Object; 

Obviously, the GetMethod function is quite fragile and can be modified as the compiler generates expressions. I am interested in knowing the reason for the change and how I can reorganize GetMethod so that it is more resistant to the expression tree generated by the compiler.

+5
source share
1 answer

I am interested to know the reason for the change.

As with .NET 4.5, there are two ways to make a delegate from MethodInfo :

  • Instance method on MethodInfo and
  • Delegate.CreateDelegate static method

It looks like Microsoft has decided to switch from using # 2 to using # 1 for some reason (this is probably more efficient).

how could I reorganize GetMethod to be more resistant to the expression tree generated by the compiler?

You can use the expression tree file and look for method information this way.

+4
source

All Articles