The problem is that a MethodCallExpression has to actually be a method. Consider:
public static void Main() { Express(str => str.Length); Console.ReadLine(); } static void Express(Expression<Func<String, Int32>> expression) { // Outputs: PropertyExpression (Which is a form of member expression) Console.WriteLine(expression.Body.GetType()); Console.ReadLine(); }
Expressions are determined at compile time, which means when I say str => str.Length I'm calling a property on str and so the compiler resolves this to a MemberExpression.
If I instead change my lambda to look like this:
Express(str => str.Count());
Then the compiler understands that I'm calling Count() on str and so it resolves to a MethodCallExpression ... because it's actually a method.
Note though, that this means you can't really 'convert' expressions from one type to another, any more than you can 'convert' a String into an Int32. You can do a parse, but I think you get that that's not really a conversation...
...that said, you can BUILD a MethodCallExpression from nothing, which is helpful in some cases. For example, let's build the lambda:
(str, startsWith) => str.StartsWith(startsWith)
(1) First we need to start by building the two parameters: (str, startsWith) => ...
// The first parameter is type "String", and well call it "str" // The second parameter also type "String", and well call it "startsWith" ParameterExpression str = Expression.Parameter(typeof(String), "str"); ParameterExpression startsWith = Expression.Parameter(typeof(String), "startsWith");
(2) Then on the right hand side, we need to build: str.StartsWith(startsWith). First we need to use reflection to bind to the StartsWith(...) method of String that takes a single input of type String, like so:
// Get the method metadata for "StartsWith" -- the version that takes a single "String" input. MethodInfo startsWithMethod = typeof(String).GetMethod("StartsWith", new [] { typeof(String) });
(3) Now that we have the binding-metadata, we can use a MethodCallExpression to actually call the method, like so:
//This is the same as (...) => str.StartsWith(startsWith); // That is: Call the method pointed to by "startsWithMethod" bound above. Make sure to call it // on 'str', and then use 'startsWith' (defined above as well) as the input. MethodCallExpression callStartsWith = Expression.Call(str, startsWithMethod, new Expression[] { startsWith });
(4) Now we have the left side (str, startsWith) / and the right side str.StartsWith(startsWith). Now we just need to join them into one lambda. Final code:
// The first parameter is type "String", and well call it "str" // The second parameter also type "String", and well call it "startsWith" ParameterExpression str = Expression.Parameter(typeof(String), "str"); ParameterExpression startsWith = Expression.Parameter(typeof(String), "startsWith"); // Get the method metadata for "StartsWith" -- the version that takes a single "String" input. MethodInfo startsWithMethod = typeof(String).GetMethod("StartsWith", new[] { typeof(String) }); // This is the same as (...) => str.StartsWith(startsWith); // That is: Call the method pointed to by "startsWithMethod" bound above. Make sure to call it // on 'str', and then use 'startsWith' (defined above as well) as the input. MethodCallExpression callStartsWith = Expression.Call(str, startsWithMethod, new Expression[] { startsWith }); // This means, convert the "callStartsWith" lambda-expression (with two Parameters: 'str' and 'startsWith', into an expression // of type Expression<Func<String, String, Boolean> Expression<Func<String, String, Boolean>> finalExpression = Expression.Lambda<Func<String, String, Boolean>>(callStartsWith, new ParameterExpression[] { str, startsWith }); // Now let's compile it for extra speed! Func<String, String, Boolean> compiledExpression = finalExpression.Compile(); // Let's try it out on "The quick brown fox" (str) and "The quick" (startsWith) Console.WriteLine(compiledExpression("The quick brown fox", "The quick")); // Outputs: "True" Console.WriteLine(compiledExpression("The quick brown fox", "A quick")); // Outputs: "False"
Update Well, maybe something like this might work:
class Program { public void DoAction() { Console.WriteLine("actioned"); } public delegate void ActionDoer(); public void Do() { Console.ReadLine(); } public static void Express(Expression<Func<Program, ActionDoer>> expression) { Program program = new Program(); Func<Program, ActionDoer> function = expression.Compile(); function(program).Invoke(); } [STAThread] public static void Main() { Express(program => program.DoAction); Console.ReadLine(); } }
Update: Came across something on accident. Consider this code:
public static String SetPropertyChanged<T>(Expression<Func<T, Object>> expression) { UnaryExpression convertExpression = (UnaryExpression)expression.Body; MemberExpression memberExpression = (MemberExpression)convertExpression.Operand; return memberExpression.Member.Name; ... }
The input is a simple lambda for WPF:
base.SetPropertyChanged(x => x.Visibility);
since I'm projecting into an Object, I noticed that visual studio converts this into a UnaryExpression, which I think is the same problem you're running into. If you put a break-point and examine the actual expression (in my case) it says x => Convert(x.Visibility). The problem is the Convert (which is effectively just a cast to a currently unknown type). All you have to do is remove it (as I do in the code above by using the Operand member, and you should be all set. Maybe you'll have your MethodCallExpression.