本文主要以CSharp语言为主,首先假设这样简单的CLASS为示例:
1: public class Person
2: {3: public void Action()
4: {5: Console.WriteLine("Run");
6: } 7: }在.net framework 1.1 到2.0 下,我们用CSharp常规反射调用Action方法如下:
1: [Test]2: public void TestGeneral()
3: {4: var p = new Person();
5: Type t = p.GetType();6: var m = t.GetMethod("Action", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
7: m.Invoke(p, null);
8: }
使用Delegate,在多次调用下 更高效:
1: [Test]2: public void TestReflectionWithDelegate()
3: {4: var p = new Person();
5: Type t = p.GetType();6: var actionmethod = (Action)Delegate.CreateDelegate(typeof(Action), p, "Action");
7: actionmethod(); 8: }然后还可使用IL Emit来实现,DynamicMethod, 关于Emit你可以去MSDN了解,以及<<C# 4.0 in a Nutshell>>书有介绍.
1: [Test]2: public void TestReflectionWithEmit()
3: {4: var methodinfo = typeof(Person).GetMethod("Action", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
5: DynamicMethod method = new DynamicMethod("Action2", null, null);
6: ILGenerator ilGenerator = method.GetILGenerator(); 7: 8: ConstructorInfo ci = typeof(Person).GetConstructor(new Type[0]);
9: ilGenerator.Emit(OpCodes.Newobj, ci);10: ilGenerator.EmitCall(OpCodes.Call, methodinfo, null);
11: ilGenerator.Emit(OpCodes.Ret); 12: 13: var runmethod = (Action)method.CreateDelegate(typeof(Action));
14: runmethod(); 15: }到.net 3.0 以后,我们可以使用Expression Tree来实现,这里直接使用了是DynamicMethodExecutor,参考老赵的文章,这样更加简洁
1: [Test]2: public void TestReflectionWithLinqExpression()
3: {4: var methodInfo = typeof(Person).GetMethod("Action", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
5: var executor = new DynamicMethodExecutor(methodInfo);
6: 7: var p = new Person();
8: executor.Execute(p, null);
9: }
DynamicMethodExecutor类
public class DynamicMethodExecutor
{private Func<object, object[], object> m_execute;
public DynamicMethodExecutor(MethodInfo methodInfo) {this.m_execute = this.GetExecuteDelegate(methodInfo);
}
public object Execute(object instance, object[] parameters)
{return this.m_execute(instance, parameters);
}
private Func<object, object[], object> GetExecuteDelegate(MethodInfo methodInfo)
{ // parameters to executeParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");
ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
// build parameter list List<Expression> parameterExpressions = new List<Expression>();ParameterInfo[] paramInfos = methodInfo.GetParameters();
for (int i = 0; i < paramInfos.Length; i++)
{ // (Ti)parameters[i]BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType);
parameterExpressions.Add(valueCast);
}
// non-instance for static method, or ((TInstance)instance) Expression instanceCast = methodInfo.IsStatic ? null : Expression.Convert(instanceParameter, methodInfo.ReflectedType); // static invoke or ((TInstance)instance).MethodMethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions);
// ((TInstance)instance).Method((T0)parameters[0], (T1)parameters[1], ...)if (methodCall.Type == typeof(void))
{Expression<Action<object, object[]>> lambda =
Expression.Lambda<Action<object, object[]>>(
methodCall, instanceParameter, parametersParameter);
Action<object, object[]> execute = lambda.Compile();
return (instance, parameters) => {execute(instance, parameters);
return null;
};
}
else {UnaryExpression castMethodCall = Expression.Convert(
methodCall, typeof(object));
Expression<Func<object, object[], object>> lambda =
Expression.Lambda<Func<object, object[], object>>(
castMethodCall, instanceParameter, parametersParameter);
return lambda.Compile();}
}
}
到.net 4.0有DLR,CSharp多了dynamic关键字,很多工作交给编译器去做了,代码更多简洁:
1: [Test]2: public void TestReflectionWithDynamic()
3: {4: dynamic p = new Person();
5: p.Action(); 6: } 这时在VS中使用dynamic,这时成员是没有智能提示的。这里我们反射的成员是public,当你遇到private在dynamic,将会有这样的exception:
“…inaccessible due to its protection level” ,当然也有办法你可以参考这篇文章。所有UnitTest都输出同样的结果。
希望这篇POST对您开发有帮助。
作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog。
浙公网安备 33010602011771号