Optimize MethodInfo.Invoke when method info is only known at runtime - c#

I am using reflection to call methods, and invoking the methods using Invoke() doesn't do it for me, too slow. I generate thousands - millions of method calls, it is a test automation tool. At compile time I have no clue about the method name, parameter type(s) or return type. So Jon Skeet's article on using delegates to cache reflection is no help here.
Here is what I have:
foreach (MethodInfo method in _methods)
{
foreach (var p in method.GetParameters())
{
var paramValue = Utils.RandomizeParamValue(p.ParameterType.Name);
parameters.Add(paramValue);
}
var result = method.Invoke(_objectInstance, parameters.ToArray());
//_objectInstance is the class instance of which the method is a member of.
}
I have researched the DLR (ExpandoObject, DynamicObject) but I am not sure it has what I am looking for. What I am looking for is a way to bypass the overhead of reflection, or cache method invocations, even if it turns out be an ugly hack. Is there a common hack that I have missed? Could I go down to IL level and do some tricks there?

One option is to use expression tree to build delegate that will call your methods. MSDN have introduction in Expression Trees article and in particular you'll need MethodCallExpression
Create an expression sample (from MethodCallExpression article):
string[,] gradeArray =
{ {"chemistry", "history", "mathematics"}, {"78", "61", "82"} };
var arrayExpression = Expression.Constant(gradeArray);
// Create a MethodCallExpression that represents indexing
// into the two-dimensional array 'gradeArray' at (0, 2).
// Executing the expression would return "mathematics".
var methodCallExpression = Expression.ArrayIndex(
arrayExpression,
Expression.Constant(0),
Expression.Constant(2));
Compile an expression to delegate sample (from main article):
Expression<Func<int, bool>> expr = num => num < 5;
Func<int, bool> result = expr.Compile();
Console.WriteLine(result(4));

Related

Does the LINQ Expression API offer no way to create a variable?

I want to validate my assumption that the LINQ Expression API does not have any means for us to create an expression that represents the creation of a local variable.
In other words, you cannot create an expression to represent:
int local;
since that is a variable declaration statement, and the API does not support statement lambdas. The only state that a lambda expression, as represented by the LINQ Expression API (and not a delegate instance) can work with is parameters it receives and the captured variables it receives via a closure.
Is my assumption (based on a few months of practice of the LINQ Expression API) correct?
False. There are some overloads of Expression.Block to do it.
What is true is that you can't create a lambda expression through the use of the C# compiler that has a variable, but that is a limitation of the compiler.
So you can't
Expression<Func<int>> exp = () => {
int v = 1;
return v;
};
but you can
var variable = Expression.Variable(typeof(int));
var lambda = Expression.Lambda<Func<int>>(
Expression.Block(
new[] { variable },
Expression.Assign(variable, Expression.Constant(1)),
variable)); // With lambda expressions, there is an implicit
// return of the last value "loaded" on the stack
since that is a variable declaration statement, and the API does not support statement lambdas.
This was true in .NET < 4.0 . In .NET 4.0 Microsoft added Expression methods to build nearly everything that can be present in the body of a method (there are some missing "things", like unsafe code keywords/operators, plus there are the primitives but there aren't complex constructs like the for or lock, that can be built on top of other constructs). Note that 90% of those added things are incompatible with LINQ-to-SQL/EF.
Well, you can use Expression.Block to declare a block which contains local variables...
For example:
using System;
using System.Linq.Expressions;
public class Test
{
static void Main()
{
var x = Expression.Variable(typeof(int), "x");
var assignment1 = Expression.Assign(x, Expression.Constant(1, typeof(int)));
var assignment2 = Expression.Assign(x, Expression.Constant(2, typeof(int)));
var block = Expression.Block(new[] { x }, new[] { assignment1, assignment2 });
}
}
That builds an expression tree equivalent to:
{
int x;
x = 1;
x = 2;
}
The C# compiler doesn't use this functionality within lambda expression conversions to expression trees, which are currently still restricted to expression lambdas, as far as I'm aware.

Getting method name from Expression

Given the following method signature:
string GetActionName<TController, T1, TResult>(Expression<Func<TController, Func<T1, TResult>>> expression)
How can I get the method name from the following implementation:
GetActionName<EventsController, int, IEnumerable<EventDto>>(c => c.GetEventsByIdLocation);
Where GetEventsById has the signature of:
IEnumerable<EventDto> GetEventsByIdLocation(int id)
My current attempt is giving me the exception:
Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.MemberExpression'.
var convertExpression = (UnaryExpression)expression.Body;
var memberExpression = (MemberExpression)convertExpression.Operand;
return memberExpression.Member.Name;
The main problem is that in your call, you are not actually calling the method, but returning it. This caused the expression tree to contain a call to a method called CreateDelegate.
Once we have that in our methodCallExpression we need to extract the object, and read its value, which is your method.
Disclaimer: This worked for me with a scenario that I think was equal to yours. If it, however, is the best way to solve the larger problem I do not know. It seems to be fairly slow.
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var constantExpression = (ContantExpression)methodCallExpression.Object;
var methodInfo = (MethodInfo)constantExpression.Value;
return methodInfo.Name
Another option would be to provide an actual method call to the method, like so:
GetActionName<EventsController, IEnumerable<EventDto>>(
c => c.GetEventsByIdLocation(0));
Which would require you to change the method to:
string GetActionName<TController, TResult>(
Expression<Func<TController, TResult>> expression)
{
return ((MethodCallExpression)expression.Body).Method.Name;
}
This solution will probably perform a lot faster. Allthough I havn't done any benchmarks or anything. Also, this option does not tie you to only being able to get the names of methods that take one int parameter.

Getting the values of method parameters inside expression trees

I'm messing around with expression trees, but I'm little stuck.
I have this expression:
Expression<Func<IX, int>> expr = i => i.GetAll(1, b, method());
Where :
int b = 2;
public static int method()
{
return 3;
}
public interface IX
{
int GetAll(int a, int b, int c);
}
Now I want to get name of the method and values of parameters for this method. Name of the method is easy, but parameter values are harder part. I know I can parse them myself, but I would need to handle all cases (ConstantExpression, MemberExpression, MethodCallExpression and maybe more I'm not aware of). So I was thinking if there was "general" way to get their values. eg 1, 2, 3.
You can get the arguments of the MethodCallExpression in question
and create compiled Func<object>s from them (boxing value-types if necessary), which can then be evaluated.
E.g.:
var args = from arg in ((MethodCallExpression)expr.Body).Arguments
let argAsObj = Expression.Convert(arg, typeof(object))
select Expression.Lambda<Func<object>>(argAsObj, null)
.Compile()();
This will obviously blow up if the expression's body is not a method-call expression or if any of the arguments to the method cannot be evaluated as is (e.g. if they depend on the argument to the expression).
Obviously, you can do a better job if you know the types of the arguments to the method beforehand. For your specific example, this should work:
var args = from arg in ((MethodCallExpression)expr.Body).Arguments
select Expression.Lambda<Func<int>>(arg, null)
.Compile()();
Can you not just get all the parameters and then compile and execute them? I don't see how it would be possible to get all the values without executing if they can be method calls.

Replacing parameters in a lambda expression

I had a part of code that takes in lambda expressions at runtime, which I can then compile and invoke.
Something thing;
Expression<Action<Something>> expression = (c => c.DoWork());
Delegate del = expression.Compile();
del.DynamicInvoke(thing);
In order to save execution time, I stored those compiled delegates in a cache, a Dictionary<String, Delegate> which the key is the lambda expression string.
cache.Add("(Something)c => c.DoWork()", del);
For exact same calls, it worked fine. However I realized that I could receive equivalent lambdas, such as "d => d.DoWork()", which I should actually use the same delegate for, and I wasn't.
This got me wondering if there was a clean way (read "not using String.Replace", I already did that as a temporary fix) to replace the elements in a lambda expression, like maybe replacing them by arg0 so that both
(c => c.DoWork()) and (d => d.DoWork())
are transformed and compared as (arg0 => arg0.DoWork()) by using something fuctionnally similar to injecting a Expression.Parameter(Type, Name) in a lambda.
Is that possible ? (Answers can include C#4.0)
I used strings, since it was the easisest way for me. You can't manually change the name of the parameter expression (it has the "Name" property, but it is read-only), so you must construct a new expression from pieces. What I did is created a "nameless" parameter (actually, it gets an autogenerated name in this case, which is "Param_0") and then created a new expression almost the same as the old one, but using the new parameter.
public static void Main()
{
String thing = "test";
Expression<Action<String>> expression = c => c.ToUpper();
Delegate del = expression.Compile();
del.DynamicInvoke(thing);
Dictionary<String, Delegate> cache = new Dictionary<String, Delegate>();
cache.Add(GenerateKey(expression), del);
Expression<Action<String>> expression1 = d => d.ToUpper();
var test = cache.ContainsKey(GenerateKey(expression1));
Console.WriteLine(test);
}
public static string GenerateKey(Expression<Action<String>> expr)
{
ParameterExpression newParam = Expression.Parameter(expr.Parameters[0].Type);
Expression newExprBody = Expression.Call(newParam, ((MethodCallExpression)expr.Body).Method);
Expression<Action<String>> newExpr = Expression.Lambda<Action<String>>(newExprBody, newParam);
return newExpr.ToString();
}
There's more to a lambda expression than just the text. Lambdas are re-written by the compiler into something much more complicated. For example, they may close over variables (which could include other delegates). This means that two lambdas could look exactly the same, but perform completely different actions.
So you might have luck caching your compiled expression, but you need to give them a more meaningful name for the key than just the text of the expression. Otherwise no amount of argument substitution will help you.

What is the best way to ReadLine by Expression Tree?

If I want to get a user input from Console to my Expression Tree. What is the best way to do it? and how to make variable 'name' duck typing?
Here are my code.
using System;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.Linq;
using Microsoft.Linq.Expressions;
namespace ExpressionTree
{
class Program
{
static void Main(string[] args)
{
List<Expression> statements = new List<Expression>();
// Output
MethodInfo Write = typeof(System.Console).GetMethod("Write", new Type[] { typeof(string) });
ConstantExpression param = Expression.Constant("What is your name? ", typeof(string));
Expression output = Expression.Call(null, Write, param);
statements.Add(output);
// Input
MethodInfo ReadLine = typeof(System.Console).GetMethod("ReadLine");
ParameterExpression exprName = Expression.Variable(typeof(String), "name");
Expression exprReadLine = Expression.Call(null, ReadLine);
// .NET 4.0 (DlR 0.9) from Microsoft.Scripting.Core.dll
// Expression.Assign and Expression.Scope
ScopeExpression input = Expression.Scope(Expression.Assign(exprName, exprReadLine), exprName);
statements.Add(input);
// Create the lambda
LambdaExpression lambda = Expression.Lambda(Expression.Block(statements));
// Compile and execute the lambda
lambda.Compile().DynamicInvoke();
Console.ReadLine();
}
}
}
Expression trees are designed to perform a fixed operation - in particular, the member-access is going to want a known MemberInfo (etc) at the point of expression tree creation (since they are immutable).
You could duplicate the generated code from dynamic if you are playing with 4.0, but to be honest, the better approach in this scenario is simply: don't use an expression tree.
Either reflection or ComponentModel (TypeDescriptor) would be ideal for this dynamic access to a member.
Also - calling Compile on something you use only once isn't saving any time, and using DynamicInvoke isn't either... you need to use the typed delegate form (Invoke).

Categories