最近项目需要用到动态编译对象。主要场景是通过JSON数据对象,生成动态匿名对象,在通过反射方法使用匿名对象。本文Demo重点方法是 通过定义委托字段 执行委托方法。
一、参考链接
二、准备工作
为了快速编写和调试 Emit,我们需要 ReSharper 全家桶:
- ReSharper - 用于实时查看 IL 代码
- dotPeek - 免费,用于查看我们使用 Emit 生成的代码,便于对比分析
相比于原生 Visual Studio,有此工具帮助的情况下,IL 的编写速度和调试速度将得到质的提升。(当然,利用这些工具依然只是手工操作,存在瓶颈;如果你阅读完本文之后找到或编写一个新的工具,更快,欢迎与我探讨。)
三、代码
废话不多,上代码
public static void ILDemo()
{
//获取当前AppDomain
AppDomain currentAppDomain = AppDomain.CurrentDomain;
//创建程序集
AssemblyName assemblyName = new AssemblyName("MyAssembly");
assemblyName.CultureInfo = System.Globalization.CultureInfo.CurrentCulture; // = "zh-CN"
assemblyName.SetPublicKeyToken(new Guid().ToByteArray());
AssemblyBuilder assBuilder = currentAppDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
//创建模块
ModuleBuilder moduleBuilder = assBuilder.DefineDynamicModule("MyAssemblyType");
//创建类型
var typeBuilder = moduleBuilder.DefineType("MyAssemblyType.MyClass", TypeAttributes.Public);
//获取委托方法对象
var DelegateFunc = GetMethod();
//构建IL委托字段
FieldBuilder fldBuilder = typeBuilder.DefineField("DynamicField", DelegateFunc.GetType(), FieldAttributes.Public);
//构建IL委托方法
MethodBuilder myMthdBld = typeBuilder.DefineMethod(
"addtest",
MethodAttributes.Public,
typeof(object),
Type.EmptyTypes);
// 通过方法构建器获取一个MSIL生成器
ILGenerator ILout = myMthdBld.GetILGenerator();
ILout.Emit(OpCodes.Nop);
ILout.Emit(OpCodes.Ldarg_0);
ILout.Emit(OpCodes.Ldfld, fldBuilder);
//IL方法中 执行委托方法
ILout.Emit(OpCodes.Callvirt, DelegateFunc.GetType().GetMethod("Invoke"));
ILout.Emit(OpCodes.Ret);
//构建对象
Type t = typeBuilder.CreateType();
object o1 = Activator.CreateInstance(t);
//把委托方法 赋值给 DynamicField字段
t.GetField("DynamicField").SetValue(o1, DelegateFunc);
//执行o1 addtest方法
var result = t.GetMethod("addtest").Invoke(o1, null);
Console.WriteLine("result = " + result);
Console.ReadKey();
}
public static Delegate GetMethod()
{
return (new Func<object>(() =>
{
return "我是委托方法";
}));
}