Click here to Skip to main content
15,890,825 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
I am taking my first baby steps with parsing/decomposing expression trees and I'm having trouble figuring out how exactly to get access to the variable and method call in a function. Say I have this helper function:
VB.NET
Public Function HelperFunction(Of T)(ByVal exp As Expressions.Expression(Of Func(Of T))) As String
    Dim mCall As Expressions.MethodCallExpression = exp.Body
    Return mCall.ToString()
End Function

And I call it in this manner:
VB.NET
MessageBox.Show(HelperFunction(Function() "test".ToString()))

The following will be shown: "test".ToString()

What I would like to do is gain access to the instance variable ("test") and the method ("ToString") and then use reflection to call that method on that instance variable. I am pretty confident I can figure out how to use reflection to make the method call, but I'm not sure how to use the expression tree code to get the instance variable and the method called.
Posted
Comments
AspDotNetDev 10-Feb-12 21:10pm    
Note that I'm fine with a solution that uses either C# or VB.Net... I can easily translate between them.
AspDotNetDev 10-Jan-13 12:30pm    
Note to self: this may be what I'm looking for: http://www.codeproject.com/Articles/109026/Chained-null-checks-and-the-Maybe-monad

Turn on Option Strict, your code won't compile :)
Anyway, as far as I can see a MethodCallExpression[^] has an Object Property[^] and a Method Property[^], which in this case should probably hold the information you need.
Consider the following (which isn't safe to use with other lambda's):
VB
Option Strict On ' Really!

Module Module1

    Sub Main()
        Console.WriteLine(HelperFunction(Function() "test".ToString))
        ' The ToString method was called on the object 'test' of type System.String.
        Console.WriteLine(HelperFunction(Function() "test".GetType))
        ' The GetType method was called on the object 'test' of type System.String.
        'Console.WriteLine(HelperFunction(Function() Integer.MaxValue))
        ' Produces an Exception! The cast to MethodCallExpression will fail.
        Console.ReadKey()
    End Sub
    
    Public Function HelperFunction(Of T)(ByVal exp As Expressions.Expression(Of Func(Of T))) As String
        ' Now with Option Strict On we have to cast this :) <- smilies are a hidden VB feature! ;p
        Dim methodCall As Expressions.MethodCallExpression = DirectCast(exp.Body, Expressions.MethodCallExpression)
        ' Gets the object on which the method was called, which is in this case represented in a ConstantExpression.
        Dim obj As Expressions.ConstantExpression = DirectCast(methodCall.Object, Expressions.ConstantExpression)
        ' Gets the method that was called. Returns a System.Reflection.MethodInfo.
        Dim method As System.Reflection.MethodInfo = methodCall.Method
        Return String.Format("The {0} method was called on the object '{1}' of type {2}.", method.Name, obj.Value, obj.Type.FullName)
    End Function
    
End Module
This piece of code only works in your specific case. Try passing in Integer.MaxValue as a lambda and the casts will go very wrong because the exp.Body will now return a ConstantExpression[^].
I started dabbling into ExpressionTrees[^] just last week. Which helped me was this article on MSDN[^]. I recommend to click on some of the links on that page also.
As I only started with this last week I'm afraid I can't say much more on the topic. I hope this will help you on your way though. Good luck! :)
 
Share this answer
 
v4
The simplest would be:
C#
var res = exp.Compile()();

No need to do any reflection explicitly.

[EDIT]
If you want to analyze the expression tree in a specific way, you might have to write your specific visitor to traverse the expression tree. See How to: Implement an Expression Tree Visitor[^]
[END EDIT]

Cheers

Andi
 
Share this answer
 
v3
Comments
AspDotNetDev 12-Feb-12 14:50pm    
The purpose of this code is to conditionally call a chain of property/method/variable accesses (a.b.c().d.E.F). If I just wanted to execute the code, I'd just execute the code.
Andreas Gieriet 12-Feb-12 15:07pm    
I'm a bit confused with your original description of calling the instance method "Test" (which is a string...(?)).
So, you want to pass the information on the method by string?
Andi
AspDotNetDev 12-Feb-12 15:33pm    
I don't know what you mean, but the instance variable "test" is just a random instance variable. It could have been anything. A number, a string, a web request, a dragon, whatever. And the method called on it could be any valid method to call on that type (in this case, I chose to call ToString()). But, for my real use, any property or variable can also be called. And it can be a chain (e.g., "test".ToString().ToString().ToString() or myDragon.BreathFire().Fly().Whatever).
Andreas Gieriet 12-Feb-12 15:55pm    
I was confused since "..." is a string literal and not an instance variable. But now I know that I don't have to take it literally.

I think you have to write a visitor to traverse the expression tree (see How to: Implement an Expression Tree Visitor) or alike.

Cheers

Andi

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900