• 在Silverlight中使用DynamicMethod(动态方法)


         DynamicMethod 类(位于System.Reflection.Emit名空间下), 用于定义并表示一种可编译、执行和
    丢弃的动态方法。
     
         而下面是微软对于DynamicMethod的应用及其运行情况的介绍:
        
        可以使用 DynamicMethod 类在运行时生成和执行方法,而不必生成动态程序集和动态类型来包含该方
    法。回收 DynamicMethod 对象时,由实时 (JIT) 编译器创建的可执行代码也将回收。动态方法是生成和
    执行少量代码的最有效方式。
        动态方法在逻辑上与模块或类型关联。如果与模块关联,动态方法对于该模块在全局范围内有效。如果有
    足够的权限,动态方法可以跳过 JIT 编译器的可见性检查,访问具有该模块所声明类型的私有数据。可以将
    动态方法与任何模块关联,无论该模块是否由您创建。
        如果动态方法与类型关联,动态方法可以访问该类型的私有成员。除非动态方法需要访问在同一模块中声
    明的其他类型的私有数据,否则无需跳过 JIT 可见性检查。可以将动态方法与任何类型关联。
        下表显示了动态方法与模块关联或与模块中的类型关联时,在进行以及不进行 JIT 可见性检查的情况下,
    动态方法可以在模块中访问的类型成员。 
      



        动态方法对所关联的模块或包含所关联的类型的模块具有权限。 
        无需对动态方法及其参数进行命名,但是可以指定名称以协助调试(下文中将会介绍)。动态方法或其属性
    不支持自定义属性。

         这么一大块看下来,头肯定大了,而本文的例子确很简单,因为DEMO的主要代码全部取自Silverlight2 Beta2
    CHM, 本人也只是将其中的代码修饰一下并将主要的注释翻译了过来,希望能通过注释让大家明白动态方法到底如
    何写,如何用.当然因为DynamicMethod这个类的构造方法被重载了六次,而CHM中所介绍的也只是它的基本构造
    方法, 形如:   

    DynamicMethod(string name, Type returnType, Type[] parameterTypes);

        其中:
        name 就是动态方法的名称,它可为"",但不能是null;
        returnType 为动态方法的返回值类型;
        parameterTypes 为参数的类型数组;
       

        首先请大家看一下DEMO的运行截图如下:

           
        
        
        而这个DEMO的主要代码就是Example.cs, 其代码如下(相关内容详见注释):  

    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Runtime.InteropServices;

    public class Example
    {
        
    // 下面的构造函数和公有属性用于将动态方法绑定到对象实例时使用
        public int Test;
        
    public Example(int test)
        {
            
    this.Test = test;
        }

        
    // 下面的代理(delegate)用于调用动态方法
        private delegate long Square(int input);
        
    private delegate int Bound(int input);
        
    private delegate int Unbound(Example target, int input);

        
    /// <summary>
        
    /// 动态方法简单调用
        
    /// </summary>
        
    /// <param name="outputBlock"></param>
        public static void Demo1(System.Windows.Controls.TextBlock outputBlock)
        {
            outputBlock.Text 
    += "例子 1 : 动态方法简单调用\n\n";

            
    // 例子 1: 简单的动态方法
            
    // 创建一个动态方法所使用的参数类型数组,因为当前例子中只有一个参数(int 类型),所
            
    // 以数组中将会只有一个类型
            Type[] methodArgs = { typeof(int) };

            
    // 创建一个动态方法(DynamicMethod)。
            
    // 在这个例子中, 方法名称为SquareIt(平方运算).
            
    // 另外,动态方法名称不是必填项. 因为系统不会按方法名称来调用动态方法(而是采用delegate).
            
    // 还有就是两个动态方法可以使用同一个方法名称.不过,这个方法名称会在调用堆栈(calls stacks)
            
    // 中出现,这样便于进行调试
            
    //
            
    // 在这个例中,动态方法的返回类型是Long [如下typeof(long)]. 
            System.Reflection.Emit.DynamicMethod squareIt = new System.Reflection.Emit.DynamicMethod(
                
    "SquareIt",
                
    typeof(long),
                methodArgs
            );

            
    // 下面是SquareIt(平方运算)的函数内容.
            
    // 在这个例子中, 使用ILGenerator生成 MSIL(MS中间语言). 
            
    // DynamicMethod has an associated type DynamicILInfo that can be used in conjunction with 
            
    // unmanaged code generators.
            
    //
            
    // MSIL 加载该参数(Integer)到堆栈上 , 并将其转换成为Long 类型. duplicates(复制) 栈顶元素.
            
    // 然后将栈顶的两个元素的乘积(平方运算)压入堆栈(返回结果时使用)
            ILGenerator il = squareIt.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Conv_I8);
            il.Emit(OpCodes.Dup);
            il.Emit(OpCodes.Mul);
            il.Emit(OpCodes.Ret);

            
    // 为上面的方法创建一个代码并将其绑定到Square的实例上. 
            
    // Creating the delegate completes the method, and any further 
            
    // attempts to change the method (for example, by adding more
            
    // MSIL) are ignored. 
            
    //
            Square invokeSquareIt =
                (Square)squareIt.CreateDelegate(
    typeof(Square));

            
    // 下面的代码显示了如使用 Square delegate,

            outputBlock.Text 
    += String.Format("123456789 squared = {0}\n",
                invokeSquareIt(
    123456789));

            
    // 当然绑定代理也可以使用 Func (能生成带单一参数且有返回类型的泛型代理),如下:
            Func<intlong> invokeGeneric =
                (Func
    <intlong>)squareIt.CreateDelegate(typeof(Func<intlong>));

            outputBlock.Text 
    += String.Format("987654321 squared = {0}\n",
                invokeGeneric(
    987654321));

        }

        
    /// <summary>
        
    /// 对象实例绑定调用
        
    /// </summary>
        
    /// <param name="outputBlock"></param>
        public static void Demo2(System.Windows.Controls.TextBlock outputBlock)
        {
            outputBlock.Text 
    += "\n例子 2: 对象实例绑定调用\n\n";

            
    // 例子 2: 将动态方法绑定到实例上.
            
    //
            
    // 下面语句将会创建一个指定参数类型的数组,以便将其绑定的动态方法上
            
    // 如要将方法(method)代理绑定到对象上,那么第一个参数应匹配代理要绑定的对象类型
            
    // 在下面代码中,要绑定的是Example类型的对象
            Type[] methodArgs2 = { typeof(Example), typeof(int) };

            
    // 创建动态方法, 在这个例子中, 该(动态)方法没有指定名称(为""), 
            
    // 返回值类型为Integer. 这个方法将会访问Example类的公有成员(Test)
            
    //
            System.Reflection.Emit.DynamicMethod multiplyTestField = new System.Reflection.Emit.DynamicMethod(
                
    "",
                
    typeof(int),
                methodArgs2
            );

            
    // 在这个例子中, 使用ILGenerator生成 MSIL(MS中间语言). 
            
    //
            
    // MSIL 加载第一个参数(Example类的一个实例), 然后使用这个实例来访问公有成员(Test) 
            ILGenerator ilMP = multiplyTestField.GetILGenerator();
            ilMP.Emit(OpCodes.Ldarg_0);

            FieldInfo testInfo 
    = typeof(Example).GetField("Test",
                BindingFlags.Public 
    | BindingFlags.Instance);

            
    // 加载第二个参数, 然后这两个数字会被相乘,如果返回值比INT大,则会执行截取操作,并将结果返回.
            ilMP.Emit(OpCodes.Ldfld, testInfo);
            ilMP.Emit(OpCodes.Ldarg_1);
            ilMP.Emit(OpCodes.Mul);
            ilMP.Emit(OpCodes.Ret);


            
    #region Bound1

            
    // 创建上面动态方法的代理. 
            
    // Creating the delegate completes the method, and any further 
            
    // attempts to change the method  for example, by adding more
            
    // MSIL  are ignored. 
            
    // 
            
    // 下面代码会将上面的动态方法绑定到Example 类的一个新实例上,同时将该实例的Test属性设置成42.
            
    // 这样每次代理运行时,都会调用同一个Example实例.另外这个代理将不再使用类型Example作为参数,
            
    // 因为Example的实例已绑定到了代理的Target参数上(如下面的((Example)invoke.Target).Test调用)
            
    // 因为下面的方法调用就像是隐藏了方法的第一个参数一样.
            
    // 
            
    // 下面代理被执行了两次,分别使用了不同的参数值(分别为3, 5)
            Bound invoke = (Bound)multiplyTestField.CreateDelegate(
                
    typeof(Bound), new Example(42));

            outputBlock.Text 
    += String.Format(
                
    "Example.Test = {0}; {1} * Example.Test = {2}\n",
                ((Example)invoke.Target).Test, 
    3, invoke(3));
            outputBlock.Text 
    += String.Format(
                
    "Example.Test = {0}; {1} * Example.Test = {2}\n",
                ((Example)invoke.Target).Test, 
    5, invoke(5));

            
    //修改当前实例的Test字段(42*2=84)
            ((Example)invoke.Target).Test *= 2;

            outputBlock.Text 
    += String.Format(
                
    "Example.Test = {0}; {1} * Example.Test = {2}\n\n",
                ((Example)invoke.Target).Test, 
    5, invoke(5));

            
    #endregion

            
    #region Bound2
            
    // 下面的Example实例将会被绑定到一个Bound代理上, 然后这个代理会运行两次,
            
    // 其间对 Example的Test值进行加1操作(类似上面的*2操作)
            Example ex = new Example(5280);

            Bound another 
    =
                (Bound)multiplyTestField.CreateDelegate(
    typeof(Bound), ex);

            outputBlock.Text 
    += String.Format(
                
    "Example.Test = {0}; {1} * Example.Test = {2}\n",
                ex.Test, 
    3, another(3));

            ex.Test 
    += 1;

            outputBlock.Text 
    += String.Format(
                
    "Example.Test = {0}; {1} * Example.Test = {2}\n\n",
                ex.Test, 
    3, another(3));

            
    #endregion


            
    #region Unbound

            
    // 最后,创建一个类型Unbound的代理.而它有两个参数,一个是Example的实例,另一个是一个Integer型数据.
            
    // 下面的代理(Unbound) 将会绑定不带Example实例的方法,实相应的实例参数将会在代理执行过程中进行加载
            Unbound notBound =
                (Unbound)multiplyTestField.CreateDelegate(
    typeof(Unbound));

            outputBlock.Text 
    += String.Format("{0} * Example.Test(42) = {1}\n",
                
    10, notBound(new Example(42), 10));
            outputBlock.Text 
    += String.Format("{0} * Example.Test(56) = {1}\n",
                
    10, notBound(new Example(56), 10));

            
    #endregion
        }
    }

        代码量不是很大,但又学习又翻译却用了一些时间,希望大家见谅:)    
        当然如下链接是它的一些在线文档:
        
        http://msdn.microsoft.com/zh-cn/library/system.reflection.emit.dynamicmethod(VS.85).aspx    
        http://msdn.microsoft.com/zh-cn/library/exczf7b9(en-us,VS.85).aspx    
        http://technet.microsoft.com/zh-cn/sysinternals/system.reflection.emit.dynamicmethod(VS.85).aspx    
        
        好了,今天的内容就先到这里了,呵呵:)    
        Demo源码包,请点击这里.
       

  • 相关阅读:
    spring boot cli 知识点
    OSX Homebrew 安装 Spring Boot CLI
    前端重定向,index.html文件被浏览器缓存,导致整个应用都是旧的
    单页面应用,接入cdn
    Spring Cloud 之 Hystrix 知识点:隔离、熔断、降级
    Spring Cloud 之 Ribbon 知识点:服务器负载均衡
    Spring Cloud 之 Feign 知识点:封装了 REST 调用
    spring cloud 学习资料
    Gradle 知识点
    Gradle 学习资料
  • 原文地址:https://www.cnblogs.com/daizhj/p/1224818.html
Copyright © 2020-2023  润新知