Accessing the caller from MethodCallExpression
I am trying to learn about expression trees and I have created a method that takes
Expression<Func<bool>>
and executes it if it meets some conditions - see the code below.
private static void TryCommand(Expression<Func<bool>> expression)
{
var methodCallExpression = expression.Body as MethodCallExpression;
if (methodCallExpression == null)
{
throw new ArgumentException("expression must be a MethodCallExpression.");
}
if (methodCallExpression.Object.Type != typeof (MyClass))
{
throw new ArgumentException("expression must be operating on an instanceof MyClass.");
}
var func = expression.Compile();
var success = func.Invoke();
if(!success)
{
Console.WriteLine(methodCallExpression.Method.Name + "() failed with error code " + (func.Target as MyClass).GetError());
}
}
The problem is that
(func.Target as MyClass)
is null. Clearly I am doing something wrong! How do I access the instance this method is running on?
source to share
The target of a method call is an instance of MyClass, but the delegate itself is not a method call. This is what the method call will perform when it is executed.
If you look at func.Target you will see System.Runtime.CompilerServices.ExecutionScope .
Now you can check this, apply to it, and then get either locales or globals (not sure) to get the target. However, I suspect it would be easier to change the usage Func<int>
(or any other type of error code) and return the error code when you execute the delegate in the first place. Then you don't even need an expression tree.
EDIT: Given your comments, I would suggest:
public static void TryCommand(Expression<Func<MyClass,bool>> command,
MyClass c)
{
// Code as before to find the method name etc.
Func<MyClass, bool> compiled = command.Compile();
if (!compiled(c))
{
Console.WriteLine(methodCallExpression.Method.Name
+ "() failed with error code " + c.GetError());
}
}
Then you call it with:
TryCommand(x => x.SomeMethod(), myClass);
source to share
Akash, if you have a MethodCallExpression, just restore the calling method. You have to rebuild the MemberExpression and build an expression tree that evaluates it.
See the code below:
MethodCallExpression methodCallExpression = (MethodCallExpression)expression.Body;
MemberExpression memberExpression = (MemberExpression)methodCallExpression.Object;
Expression<Func<Object>> getCallerExpression = Expression<Func<Object>>.Lambda<Func<Object>>(memberExpression);
Func<Object> getCaller = getCallerExpression.Compile();
MyClass caller = (MyClass)getCaller();
Hope it helps,
Ricardo Lacerda Castelo Branco
source to share
The target is null because the method is static. In reflection, Invoke (..) on static MethodInfo ignores the target. This is likely an extension method, in which case the intended target is the first argument.
Since most LINQ is based on extension methods, you'll see this quite often with reflection.