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.
When you want to have a richer interaction, you need to use Expression Trees. Expression Trees represent code as a structure that you can examine, modify, or execute. These tools give you the power to manipulate code during run time. You can write code that examines running algorithms, or injects new capabilities.
The main use of these expression trees is that it is used to evaluate, analyze and modify the various expressions. It is also used to find out the associativity of each operator in the expression. For example, the + operator is the left-associative and / is the right-associative.
Expression trees allow you to build code dynamically at runtime instead of statically typing it in the IDE and using a compiler. They are well explained in the documentation.
Expression Trees was first introduced in C# 3.0 (Visual Studio 2008), where they were mainly used by LINQ providers. Expression trees represent code in a tree-like format, where each node is an expression (for example, a method call or a binary operation such as x < y).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With