My application works with loading dll’s dynamically, based on settings
from the database (file, class and method names). To facilitate, expedite and reduce the use of reflection I would like to have a cache….
Following the idea that using:
MethodInfo.Invoke
Is nothing performative ( Reflection Performance – Create Delegate (Properties C#))
I would like to translate any call to methods. I thought of something that would work like this:
public static T Create<T>(Type type, string methodName) // or
public static T Create<T>(MethodInfo info) // to use like this:
var action = Create<Action<object>>(typeof(Foo), "AnySetValue");
One requirement is that all the parameters, can be object.
I’m trying to deal with expressions, and so far I have something like this:
private void Sample()
{
var assembly = Assembly.GetAssembly(typeof(Foo));
Type customType = assembly.GetType("Foo");
var actionMethodInfo = customType.GetMethod("AnyMethod");
var funcMethodInfo = customType.GetMethod("AnyGetString");
var otherActionMethod = customType.GetMethod("AnySetValue");
var otherFuncMethodInfo = customType.GetMethod("OtherGetString");
var foo = Activator.CreateInstance(customType);
var actionAccessor = (Action<object>)BuildSimpleAction(actionMethodInfo);
actionAccessor(foo);
var otherAction = (Action<object, object>)BuildOtherAction(otherActionMethod);
otherAction(foo, string.Empty);
var otherFuncAccessor = (Func<object, object>)BuildFuncAccessor(funcMethodInfo);
otherFuncAccessor(foo);
var funcAccessor = (Func<object,object,object>)BuildOtherFuncAccessor(otherFuncMethodInfo);
funcAccessor(foo, string.Empty);
}
static Action<object> BuildSimpleAction(MethodInfo method)
{
var obj = Expression.Parameter(typeof(object), "o");
Expression<Action<object>> expr =
Expression.Lambda<Action<object>>(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method), obj);
return expr.Compile();
}
static Func<object, object> BuildFuncAccessor(MethodInfo method)
{
var obj = Expression.Parameter(typeof(object), "o");
Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(
Expression.Convert(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method),
typeof(object)),
obj);
return expr.Compile();
}
static Func<object, object, object> BuildOtherFuncAccessor(MethodInfo method)
{
var obj = Expression.Parameter(typeof(object), "o");
var value = Expression.Parameter(typeof(object));
Expression<Func<object, object, object>> expr =
Expression.Lambda<Func<object, object, object>>(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method,
Expression.Convert(value, method.GetParameters()[0].ParameterType)),
obj, value);
return expr.Compile();
}
static Action<object, object> BuildOtherAction(MethodInfo method)
{
var obj = Expression.Parameter(typeof(object), "o");
var value = Expression.Parameter(typeof(object));
Expression<Action<object, object>> expr =
Expression.Lambda<Action<object, object>>(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method,
Expression.Convert(value, method.GetParameters()[0].ParameterType)),
obj,
value);
return expr.Compile();
}
public class Foo
{
public void AnyMethod() {}
public void AnySetValue(string value) {}
public string AnyGetString()
{ return string.Empty; }
public string OtherGetString(string value)
{ return string.Empty; }
}
Is there any way to simplify this code? (I believe it is possible to create a method only using generic..) And when you have 3, 4, 5, any parameters as I do?
I was thinking, what if there was something like this:
but I’ll have more one parameter (in action or function), this parameter (first parameter) an object to perform.
Is this possible?
I have made a sample program that fulfills all your requirements (I think!)
DelegateBuilder class:
How it works
The core is the BuildDelegate method:
static T BuildDelegate<T>(MethodInfo method)Example call:
var action = BuildDelegate<Action<object, int>>(mi);Rules for parameters:
If the method passed is an instance method, first parameter of the generated delegate will accept the instance of the object, that contains the method itself. All other parameter will be passed to the method.
If the method passed is a static method, then all parameters of the generated delegate will be passed to the method.
Missing parameters will have default values passed.