本文主要以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

posted on 2011-04-25 22:58  PetterLiu  阅读(1031)  评论(0编辑  收藏  举报