在Silverlight中使用DynamicMethod(动态方法)
DynamicMethod 类(位于System.Reflection.Emit名空间下), 用于定义并表示一种可编译、执行和
丢弃的动态方法。
而下面是微软对于DynamicMethod的应用及其运行情况的介绍:
可以使用 DynamicMethod 类在运行时生成和执行方法,而不必生成动态程序集和动态类型来包含该方
法。回收 DynamicMethod 对象时,由实时 (JIT) 编译器创建的可执行代码也将回收。动态方法是生成和
执行少量代码的最有效方式。
动态方法在逻辑上与模块或类型关联。如果与模块关联,动态方法对于该模块在全局范围内有效。如果有
足够的权限,动态方法可以跳过 JIT 编译器的可见性检查,访问具有该模块所声明类型的私有数据。可以将
动态方法与任何模块关联,无论该模块是否由您创建。
如果动态方法与类型关联,动态方法可以访问该类型的私有成员。除非动态方法需要访问在同一模块中声
明的其他类型的私有数据,否则无需跳过 JIT 可见性检查。可以将动态方法与任何类型关联。
下表显示了动态方法与模块关联或与模块中的类型关联时,在进行以及不进行 JIT 可见性检查的情况下,
动态方法可以在模块中访问的类型成员。
动态方法对所关联的模块或包含所关联的类型的模块具有权限。
无需对动态方法及其参数进行命名,但是可以指定名称以协助调试(下文中将会介绍)。动态方法或其属性
不支持自定义属性。
这么一大块看下来,头肯定大了,而本文的例子确很简单,因为DEMO的主要代码全部取自Silverlight2 Beta2
CHM, 本人也只是将其中的代码修饰一下并将主要的注释翻译了过来,希望能通过注释让大家明白动态方法到底如
何写,如何用.当然因为DynamicMethod这个类的构造方法被重载了六次,而CHM中所介绍的也只是它的基本构造
方法, 形如:
其中:
name 就是动态方法的名称,它可为"",但不能是null;
returnType 为动态方法的返回值类型;
parameterTypes 为参数的类型数组;
首先请大家看一下DEMO的运行截图如下:
而这个DEMO的主要代码就是Example.cs, 其代码如下(相关内容详见注释):
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
}
}
代码量不是很大,但又学习又翻译却用了一些时间,希望大家见谅:)
当然如下链接是它的一些在线文档:
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源码包,请点击这里.