在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 < int long >  invokeGeneric  =
            (Func
< int long > )squareIt.CreateDelegate( typeof (Func < int long > ));

        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
    }
}

    代码量不是很大,但又学习又翻译却用了一些时间,希望大家见谅:)    


本文转自 daizhenjun 51CTO博客,原文链接:http://blog.51cto.com/daizhj/83079,如需转载请自行联系原作者
相关文章