• 反射发送实战(-)InvokeMember [转载]


    http://blog.codelphi.com/tmfc/archive/2004/08/24/20075.aspx

    反射是.net中的高级功能之一,利用反射可以实现许多以前看来匪夷所思的功能,下面是我看了《Programming C#》(O'Reilly)之后对于反射的一点实践,本想直接做个应用程序来说明问题,但苦于工作繁忙并考虑到以简单为主,故先对反射发送(reflection emit)的使用做一些介绍。文章最后再给出一个实例。

     

    下面的程序在运行时生成了一个Test.cs文件,并调用csc编译成Test.dll文件,然后利用Type.InvokeMember()方法调用其中的SayHello()方法,然后和原始方法对比一下性能。

    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Reflection;

    namespace InvokeMember
    {
       
    ///


       
    /// Class1 的摘要说明。
       
    ///

        class Class1 { ///
           
    /// 应用程序的主入口点。
           
    ///

            [STAThread]
           
    static void Main(string[] args)
            {
               
    //循环次数
                const int iterations = 100;
               
    //计算所用时间
                DateTime startTime = DateTime.Now;
               
    for(int i = 0;i< iterations;i++) { //对照方法
                    Console.WriteLine("Hello,World");
                }
                TimeSpan elasped
    = DateTime.Now - startTime;
                Console.WriteLine(
    "Looping Elapsed milliseconds:" + elasped.TotalMilliseconds + "for {0} iterations",iterations);
               
               
    //使用反射发送
                ReflectionTest t = new ReflectionTest();
               
    //计算所用时间
                startTime = DateTime.Now;
               
    for(int i = 0;i < iterations;i++)
                {
                    t.DoOperation();
                }
               
                elasped
    = DateTime.Now - startTime;

                Console.WriteLine(
    "Looping Elapsed milliseconds:" + elasped.TotalMilliseconds + "for {0} iterations",iterations);
                Console.ReadLine();
            }
        }

       
    ///
       
    /// Reflection 的摘要说明。
       
    ///

        public class ReflectionTest
        {
           
    //保存动态生成并编译的类的type对象
            Type theType = null;
           
    //保存动态生成类的实例
            object theClass = null;

           
    ///
           
    /// 供Client调用的方法
           
    ///

            public void DoOperation()
            {
               
    //未初始化
                if(theType == null)
                {
                   
    //初始化
                    GenerateCode();
                }
               
    //调用方法时的参数数组(此处为空)
                object[] arguments = new object[0];
               
    //调用动态生成类的方法
                theType.InvokeMember("SayHello",//要调用的方法名
                    BindingFlags.Default|BindingFlags.InvokeMethod,//Binding标志,具体参看msdn
                    null,//使用默认Binding对象
                    theClass,//在theClass实例上调用此方法
                    arguments//调用方法时的参数数组
                    );
            }

           
    ///
           
    /// 运行时生成代码
           
    ///

            private void GenerateCode()
            {
               
    //文件名
                string fileName = "Test";
               
    //打开文件,如果不存在,则创建
                Stream s = File.Open(fileName + ".cs",FileMode.Create);
               
    //创建一个StreamWriter来写入数据
                StreamWriter wrtr = new StreamWriter(s);
               
    //写入动态创建类的源代码
                wrtr.WriteLine("// 动态创建Test类");

               
    //类名
                string className = "TestClass";
                wrtr.WriteLine(
    "using System;");
                wrtr.WriteLine(
    "class {0}",className);
                wrtr.WriteLine(
    "{");

                wrtr.WriteLine(
    "\tpublic void SayHello()");
                wrtr.WriteLine(
    "\t{");

                wrtr.WriteLine(
    "\t\tConsole.WriteLine(\"Hello,World\");");
                wrtr.WriteLine(
    "\t}");
                wrtr.WriteLine(
    "}");

               
    //关闭StreamWriter和文件
                wrtr.Close();
                s.Close();

               
    //启动进程编译源文件
               
    //指定参数
                ProcessStartInfo psi = new ProcessStartInfo();
               
    //启动cmd.exe
                psi.FileName = "cmd.exe";
               
    //cmd.exe的参数,/c-close,完成后关闭;后为参数,指定cmd.exe使用csc来编译刚才生成的源文件
                string compileString = "/c C:\\WINNT\\Microsoft.NET\\Framework\\v1.1.4322\\csc.exe /optimize+ /target:library {0}.cs";
                psi.Arguments
    = String.Format(compileString,fileName);
               
    //运行时的风格-最小化
                psi.WindowStyle = ProcessWindowStyle.Minimized;
           
               
    //启动进程
                Process proc = Process.Start(psi);
               
    //指定当前在此进程退出前等待
                proc.WaitForExit();

               
    //从编译好的dll文件load一个Assembly
                Assembly a = Assembly.LoadFrom(fileName + ".dll");

               
    //创建类的实例
                theClass = a.CreateInstance(className);
               
    //取得此类实例的类型
                theType = a.GetType(className);
               
    //删除源文件
               
    //File.Delete(flieName + ".cs");
            }
        }
    }

    程序运行结果:

    Hello,World
    Hello,World

    .

    .

    .

    Looping Elapsed milliseconds:93.75 for 100 iterations

    Hello,World
    Hello,World

    .

    .

    .

    Looping Elapsed milliseconds:2875 for 100 iterations

    性能上不占优势,主要是因为要进行写文件和编译的工作,但是后面的方法会对性能进行优化,到最后一个方法时性能会有大幅提高,但是最后一种方法的实用性不如前两种。

  • 相关阅读:
    JSON 体验JSON (二)json格式化日期
    让D2006的控件面板回到D7的样式
    突破网站限制 复制网页内容
    欢迎光临
    加密Access数据库
    取得程序中一些特殊文件夹的位置
    连接带密码的Access数据库
    我被强暴,老公这样回答是人么?(转~非黄)
    【WinCE版凯立德】2012春季版地图下载
    刚刚拍到的日环食金星凌日
  • 原文地址:https://www.cnblogs.com/king_astar/p/58201.html
Copyright © 2020-2023  润新知