In one of my libraries, I have code that returns a 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 like the following:
public MethodInfo Func<T, R, A1>(Expression<Func<T, Func<A1, R>>> expression)
{
return GetMethod(expression);
}
This would enable the following syntax:
var methodInfo = Func<TestClass, bool, string>(x => x.AnInstanceMethodThatTakesAStringAndReturnsABool);
This worked great, until I recently upgraded the library to .Net 4.6.1 and the latest c# compiler.
In the previous version of .net, the expression would be of the form:
{x => Convert(CreateDelegate(System.Func`2[System.String, System.Boolean], x, Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String)))}
Hence my code would look for the methodInfoExpression as the last argument of the methodCallExpression.
Now, in .Net 4.6.1 (latest c# compiler), the compiler seems to be producing an expression of a different form:
{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 ConstantExpression. Looking at it - easy fix, just change to
var methodInfoExpression = (ConstantExpression)methodCallExpression.Object;
Obviously, the GetMethod function is pretty fragile and subject to changes to how the compiler generates expressions. I'm curious as to the reason for the change and how I might refactor GetMethod so that it is more resilient to the expression tree generated by the compiler.
I'm curious as to the reason for the change
As of .NET 4.5 there were two ways of making a delegate from MethodInfo
:
MethodInfo
, andDelegate.CreateDelegate
static methodIt looks like Microsoft decided to switch from using #2 to using #1, for whatever reason (it's probably more efficient).
how I might refactor
GetMethod
so that it is more resilient to the expression tree generated by the compiler?
You could use expression tree visitor, and look for the method info that way.