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.