C++/CLIVisual Studio .NET 2003WebForms.NET 1.1.NET 3.0Visual Studio 2005ADO.NET高级.NET 2.0C# 2.0开发Visual StudioWindows.NETVisual BasicASP.NETC#
具有人性化的 Emit






4.78/5 (25投票s)
2006年5月20日

73117
System.Reflection.Emit 命名空间的包装器
引言
System.Reflection.Emit
命名空间提供了在运行时创建动态程序集所需的类。它允许编译器和工具发出 MSIL,执行它并将它存储到磁盘。虽然 Emit
是一个强大的工具,但它也极其难以使用。
让我们来看一下下面的例子,它演示了“正常”的 Emit
编程方式
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace EmitDemo
{
public interface IHello
{
void SayHello(string toWhom);
}
class Program
{
static void Main(string[] args)
{
AssemblyName asmName = new AssemblyName();
asmName.Name = "HelloWorld";
AssemblyBuilder asmBuilder =
Thread.GetDomain().DefineDynamicAssembly
(asmName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule
("HelloWorld");
TypeBuilder typeBuilder = modBuilder.DefineType(
"Hello",
TypeAttributes.Public,
typeof(object),
new Type[] { typeof(IHello) });
MethodBuilder methodBuilder = typeBuilder.DefineMethod("SayHello",
MethodAttributes.Private | MethodAttributes.Virtual,
typeof(void),
new Type[] { typeof(string) });
typeBuilder.DefineMethodOverride(methodBuilder,
typeof(IHello).GetMethod("SayHello"));
ILGenerator il = methodBuilder.GetILGenerator();
// string.Format("Hello, {0} World!", toWhom)
//
il.Emit(OpCodes.Ldstr, "Hello, {0} World!");
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, typeof(string).GetMethod
("Format", new Type[] { typeof(string), typeof(object) }));
// Console.WriteLine("Hello, World!");
//
il.Emit(OpCodes.Call, typeof(Console).GetMethod
("WriteLine", new Type[] { typeof(string) }));
il.Emit(OpCodes.Ret);
Type type = typeBuilder.CreateType();
IHello hello = (IHello)Activator.CreateInstance(type);
hello.SayHello("Emit");
}
}
}
请注意,Emit
方法接受一个 OpCode
参数,以及可选的另一个参数,该参数不依赖于当前的运算上下文。因此,这种方式并非完全类型安全。
替代方案
幸运的是,还有另一种方法。 .NET 的业务逻辑工具包 提供了一个辅助类,EmitHelper,它可以让你的生活更轻松一些。它包含几乎所有 Emit
命令的类型化包装方法,并允许编写类似于 MSIL 的源代码。
以下示例展示了如何使用 EmitHelper
类与 C#、VB.NET 和 C++/CLI。
示例
C#
using System;
using BLToolkit.Reflection;
using BLToolkit.Reflection.Emit;
namespace EmitHelperDemo
{
public interface IHello
{
void SayHello(string toWhom);
}
class Program
{
static void Main(string[] args)
{
EmitHelper emit = new AssemblyBuilderHelper("HelloWorld.dll")
.DefineType ("Hello", typeof(object), typeof(IHello))
.DefineMethod(typeof(IHello).GetMethod("SayHello"))
.Emitter;
emit
// string.Format("Hello, {0} World!", toWhom)
//
.ldstr ("Hello, {0} World!")
.ldarg_1
.call (typeof(string), "Format", typeof(string),
typeof(object))
// Console.WriteLine("Hello, World!");
//
.call (typeof(Console), "WriteLine", typeof(string))
.ret()
;
Type type = emit.Method.Type.Create();
IHello hello = (IHello)TypeAccessor.CreateInstance(type);
hello.SayHello("C#");
}
}
}
VB.NET
Imports BLToolkit.Reflection
Imports BLToolkit.Reflection.Emit
Public Module Module1
Public Interface IHello
Sub SayHello(ByVal toWhom As String)
End Interface
Sub Main()
Dim assemblyHelper As AssemblyBuilderHelper = _
New AssemblyBuilderHelper("HelloWorld.dll")
Dim typeHelper As TypeBuilderHelper = _
assemblyHelper.DefineType("Hello", GetType(Object), GetType(IHello))
Dim methodHelper As MethodBuilderHelper = _
typeHelper.DefineMethod(GetType(IHello).GetMethod("SayHello"))
Dim emit As EmitHelper = methodHelper.Emitter
' string.Format("Hello, {0} World!", toWhom)
'
emit _
.ldstr("Hello, {0} World!") _
.ldarg_1 _
.call(GetType(String), "Format", GetType(String), GetType(Object))
' Console.WriteLine("Hello, World!");
'
emit _
.call(GetType(Console), "WriteLine", GetType(String)) _
.ret()
Dim type As Type = typeHelper.Create()
Dim hello As IHello = TypeAccessor.CreateInstance(type)
hello.SayHello("VB")
End Sub
End Module
C++/CLI
#include "stdafx.h"
using namespace System;
using namespace BLToolkit::Reflection;
using namespace BLToolkit::Reflection::Emit;
public interface class IHello
{
void SayHello(String ^toWhom);
};
void main()
{
AssemblyBuilderHelper ^assembly = gcnew AssemblyBuilderHelper
("HelloWorld.dll");
EmitHelper ^emit = assembly
->DefineType ("Hello", Object::typeid, IHello::typeid)
->DefineMethod(IHello::typeid->GetMethod("SayHello"))
->Emitter;
emit
// string.Format("Hello, {0} World!", toWhom)
//
->ldstr ("Hello, {0} World!")
->ldarg_1
->call (String::typeid, "Format", String::typeid, Object::typeid)
// Console.WriteLine("Hello, World!");
//
->call (Console::typeid, "WriteLine", String::typeid)
->ret()
;
Type ^type = emit->Method->Type->Create();
IHello ^hello = (IHello^)TypeAccessor::CreateInstance(type);
hello->SayHello("C++");
}