本文主要以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 execute
ParameterExpression 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).Method
MethodCallExpression 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。