我的应用程序基于设置动态加载dll
从数据库(文件,类和方法名称).为了方便,加快和减少使用反射我想要一个缓存….
从数据库(文件,类和方法名称).为了方便,加快和减少使用反射我想要一个缓存….
遵循使用:
MethodInfo.Invoke
没有什么表现(Reflection Performance – Create Delegate (Properties C#))
我想翻译任何对方法的调用.我想到了会这样工作的东西:
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");
一个要求是所有的参数,可以是对象.
我正在试图处理表达,到目前为止我有这样的事情:
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,typeof(object)),obj); return expr.Compile(); } static Func<object,object> BuildOtherFuncAccessor(MethodInfo method) { var obj = Expression.Parameter(typeof(object),"o"); var value = Expression.Parameter(typeof(object)); Expression<Func<object,object>>( Expression.Call( Expression.Convert(obj,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,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; } }
有没有办法简化这段代码? (我相信可以创建一个只使用泛型的方法..)当你有3,4,5,任何参数像我一样?
我在想,如果有这样的话呢?
但是我会有更多的参数(在动作或函数中),这个参数(第一个参数)要执行一个对象.
这可能吗?
解决方法
我已经做了一个满足您所有要求的示例程序(我想!)
class Program { class MyType { public MyType(int i) { this.Value = i; } public void SetValue(int i) { this.Value = i; } public void SetSumValue(int a,int b) { this.Value = a + b; } public int Value { get; set; } } public static void Main() { Type type = typeof(MyType); var mi = type.GetMethod("SetValue"); var obj1 = new MyType(1); var obj2 = new MyType(2); var action = DelegateBuilder.BuildDelegate<Action<object,int>>(mi); action(obj1,3); action(obj2,4); Console.WriteLine(obj1.Value); Console.WriteLine(obj2.Value); // Sample passing a default value for the 2nd param of SetSumValue. var mi2 = type.GetMethod("SetSumValue"); var action2 = DelegateBuilder.BuildDelegate<Action<object,int>>(mi2,10); action2(obj1,3); action2(obj2,4); Console.WriteLine(obj1.Value); Console.WriteLine(obj2.Value); // Sample without passing a default value for the 2nd param of SetSumValue. // It will just use the default int value that is 0. var action3 = DelegateBuilder.BuildDelegate<Action<object,int>>(mi2); action3(obj1,3); action3(obj2,4); Console.WriteLine(obj1.Value); Console.WriteLine(obj2.Value); } }
DelegateBuilder类:
public class DelegateBuilder { public static T BuildDelegate<T>(MethodInfo method,params object[] missingParamValues) { var queueMissingParams = new Queue<object>(missingParamValues); var dgtMi = typeof(T).GetMethod("Invoke"); var dgtRet = dgtMi.ReturnType; var dgtParams = dgtMi.GetParameters(); var paramsOfDelegate = dgtParams .Select(tp => Expression.Parameter(tp.ParameterType,tp.Name)) .ToArray(); var methodParams = method.GetParameters(); if (method.IsStatic) { var paramsToPass = methodParams .Select((p,i) => CreateParam(paramsOfDelegate,i,p,queueMissingParams)) .ToArray(); var expr = Expression.Lambda<T>( Expression.Call(method,paramsToPass),paramsOfDelegate); return expr.Compile(); } else { var paramThis = Expression.Convert(paramsOfDelegate[0],method.DeclaringType); var paramsToPass = methodParams .Select((p,i + 1,queueMissingParams)) .ToArray(); var expr = Expression.Lambda<T>( Expression.Call(paramThis,paramsOfDelegate); return expr.Compile(); } } private static Expression CreateParam(ParameterExpression[] paramsOfDelegate,int i,ParameterInfo callParamType,Queue<object> queueMissingParams) { if (i < paramsOfDelegate.Length) return Expression.Convert(paramsOfDelegate[i],callParamType.ParameterType); if (queueMissingParams.Count > 0) return Expression.Constant(queueMissingParams.Dequeue()); if (callParamType.ParameterType.IsValueType) return Expression.Constant(Activator.CreateInstance(callParamType.ParameterType)); return Expression.Constant(null); } }
怎么运行的
核心是BuildDelegate方法:
static T BuildDelegate< T>(MethodInfo方法)
> T是要创建的委托类型.
方法是要由生成的委托调用的方法的MethodInfo.
示例调用:var action = BuildDelegate< Action< object,int>>(mi);
参数规则:
>如果传递的方法是一个实例方法,生成的委托的第一个参数将接受包含方法本身的对象的实例.所有其他参数将被传递给该方法.>如果传递的方法是一个静态方法,那么生成的委托的所有参数将被传递给该方法.>缺少参数将传递默认值.>额外的参数将被丢弃.