.NET Emit 入门教程:第四部分:构建类型(Type)

打印 上一主题 下一主题

主题 884|帖子 884|积分 2652

前言:

在动态生成代码的过程中,构建类型(Type)是至关重要的一步。
通过使用 Emit 中的 TypeBuilder,我们可以定义和创建各种类型,包括类、布局体和接口。
本节将深入探讨如何使用 TypeBuilder 动态构建类型,并介绍其在实际应用中的重要性。
定义公用代码,生成程序集以供对照:

通过学习本系列之前的文章,我们可以轻松定义 AssemblyBuilder 程序集构建器,再通过程序集构建器,定义 ModuleBuilder 模块构建器。
下面我们先通过定义公用代码来生成程序集,以便更好的通过反编绎,来观察对照我们生成的代码。
  1. AssemblyName assName = new AssemblyName("myAssembly");
  2. AssemblyBuilder ab =<strong> AppDomain.CurrentDomain</strong>.DefineDynamicAssembly(assName, AssemblyBuilderAccess.RunAndSave);
  3. ModuleBuilder mb = ab.DefineDynamicModule("myModule","a.dll");
  4. //...今天的示例代码存放地
  5. ab.Save("a.dll");
复制代码
留意标红的部分为 .NET 版本代码,正如本系列之前文件所说,只有 .NET 版本支持程序集长期化,.NET Core 需要到9版本才支持。
.NET Core 用 AssemblyBuilder.DefineDynamicAssembly来构建。
ModuleBuilder 的几个定义方法:

1、定义罗列:
  1. EnumBuilder eb=mb.DefineEnum("bbb", ...);
复制代码
2、定义类(包括类、接口、布局体):
  1. TypeBuilder tb=mbDefineType("aaa", ...);
复制代码
3、定义内部类:
  1. TypeBuilder tb=mbDefineType("aaa", ...);
  2. TypeBuilder innerClassBuilder = tb.DefineNestedType("innerClass",...);
复制代码
下面我们使用代码对照,来学习本节内容:
1、定义罗列:
  1. EnumBuilder eb = mb.DefineEnum("MyNameSpace.MyEnum", TypeAttributes.Public, typeof(int));
  2. eb.DefineLiteral("Spring", 0);
  3. eb.DefineLiteral("Summer", 1);
  4. eb.DefineLiteral("Autumn", 2);
  5. eb.DefineLiteral("Winter", 3);
  6. Type enumType = eb.CreateType();
复制代码
对应生成的代码:

2、定义接口:
  1. TypeBuilder tb = mb.DefineType("MyNameSpace.MyInterface", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Interface);
  2. //tb.DefineField("ID", typeof(int), FieldAttributes.Public| FieldAttributes.Static| FieldAttributes.InitOnly);
  3. // 定义属性 "Name",类型为 int
  4. PropertyBuilder propertyBuilder = tb.DefineProperty("Name", PropertyAttributes.None, typeof(int), null);
  5. // 定义属性的 getter 方法
  6. MethodBuilder getterMethodBuilder = tb.DefineMethod("get_Name", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(int), Type.EmptyTypes);
  7. propertyBuilder.SetGetMethod(getterMethodBuilder);
  8. // 定义属性的 setter 方法
  9. MethodBuilder setterMethodBuilder = tb.DefineMethod("set_Name", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, null, new Type[] { typeof(int) });
  10. propertyBuilder.SetSetMethod(setterMethodBuilder);
  11. <br> //定义方法 GetMyName
  12. MethodBuilder getMyName = tb.DefineMethod("GetMyName", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(string), new Type[] { typeof(int) });
  13. tb.CreateType();
复制代码
属性的定义,需要挂接 get_XXX 和 set_XXX 两个方法,会相对显的定义贫苦了点。
对应生成的代码:

3、定义布局体
  1. // 定义结构体
  2. TypeBuilder tb = mb.DefineType("MyNameSpace.MyStruct", TypeAttributes.SequentialLayout | TypeAttributes.Public | TypeAttributes.Sealed, typeof(ValueType));
  3. // 定义字段
  4. tb.DefineField("ID", typeof(int), FieldAttributes.Public);
  5. tb.DefineField("Name", typeof(string), FieldAttributes.Public);
  6. tb.CreateType();
复制代码
对应生成的代码:

4、定义类:抽象类
  1. TypeBuilder tb = mb.DefineType("MyNameSpace.MyClassBase", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Class);
  2. tb.DefineField("ID", typeof(int), FieldAttributes.Public);
  3. tb.DefineMethod("MyProtectedMethod", MethodAttributes.<strong>Family</strong> | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(void), Type.EmptyTypes);
  4. tb.CreateType();
  5. tb.CreateType();
复制代码
MethodAttributes.Family 对应的即:protected 修饰符。
对应生成的代码:

5、定义类:并继承自抽象类:
  1. //定义基类<br>TypeBuilder tb = mb.DefineType("MyNameSpace.MyClassBase", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Class);
  2. tb.DefineField("ID", typeof(int), FieldAttributes.Public);
  3. tb.DefineMethod("MyProtectedMethod", MethodAttributes.Family | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(void), Type.EmptyTypes);
  4. Type typeBase = tb.CreateType();
  5. <br>//定义子类,继承基类
  6. TypeBuilder tbClass = mb.DefineType("MyNameSpace.MyClass", TypeAttributes.Public | TypeAttributes.Class, <strong>typeBase</strong>);
  7. //实现抽象方法
  8. MethodBuilder mbClass = tbClass.DefineMethod("MyProtectedMethod", MethodAttributes.Family | MethodAttributes.Virtual, typeof(void), Type.EmptyTypes);
  9. ILGenerator iL = mbClass.GetILGenerator();
  10. iL.Emit(OpCodes.Ret);
  11. tbClass.CreateType();
复制代码
红色标注为指定继承,接口继承一样在该参数指定。
对应生成的代码:

6、定义类:增加泛型参数指定
  1. //定义基类
  2. TypeBuilder tb = mb.DefineType("MyNameSpace.MyClassBase", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Class);
  3. tb.DefineField("ID", typeof(int), FieldAttributes.Public);
  4. tb.DefineMethod("MyProtectedMethod", MethodAttributes.Family | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(void), Type.EmptyTypes);
  5. Type typeBase = tb.CreateType();
  6. //定义子类继承基类
  7. TypeBuilder tbClass = mb.DefineType("MyNameSpace.MyClass", TypeAttributes.Public | TypeAttributes.Class, typeBase);
  8. //实现抽象方法
  9. MethodBuilder mbClass = tbClass.DefineMethod("MyProtectedMethod", MethodAttributes.Family | MethodAttributes.Virtual, typeof(void), Type.EmptyTypes);
  10. ILGenerator iL = mbClass.GetILGenerator();
  11. iL.Emit(OpCodes.Ret);
  12. // 定义泛型参数
  13. string[] typeParamNames = { "T" };
  14. GenericTypeParameterBuilder[] typeParams = tbClass.DefineGenericParameters(typeParamNames);
  15. //定义泛型方法
  16. MethodBuilder methodBuilder = tbClass.DefineMethod("GetT", MethodAttributes.Public, typeParams[0], new Type[] { typeof(object) });
  17. ILGenerator ilGenerator = methodBuilder.GetILGenerator();
  18. ilGenerator.Emit(OpCodes.Ldarg_0);
  19. ilGenerator.Emit(OpCodes.Ret);
  20. tbClass.CreateType();
复制代码
这里通过定义泛型参数,来指定我们的泛型类。
对应生成的代码:

7、通过内部类定义委托:
  1. // 定义内部类,并在内部类中定义委托类型
  2. TypeBuilder delegateBuilder = tbClass.DefineNestedType("MyNameSpace.AuthDelegate", TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.Sealed, typeof(MulticastDelegate));
  3. // 添加委托的构造函数
  4. ConstructorBuilder constructor = delegateBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) });
  5. constructor.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
  6. // 添加Invoke方法
  7. delegateBuilder.DefineMethod("Invoke", MethodAttributes.Public, typeof(bool), new Type[] { typeof(string) }).SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
  8. // 创建内部类和委托类型
  9. Type authDelegateType = delegateBuilder.CreateType();
复制代码
留意,这里是通过Type的形式,来定义委托。

因此,我们对其限定名称空间,限定其使用范围:

同时将委托定义在某个类当成员变量:

通过定义变乱,是使用委托的方式之一。
8、定义变乱:
  1. //定义事件
  2. EventBuilder eb = tbClass.DefineEvent("MyEvent", EventAttributes.None, delegateBuilder);
  3. MethodBuilder addMethod = tbClass.DefineMethod("add_OnAuth", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, typeof(void), new Type[] { delegateBuilder });
  4. ILGenerator addMethodIL = addMethod.GetILGenerator();
  5. //......
  6. addMethodIL.Emit(OpCodes.Ret);
  7. eb.SetAddOnMethod(addMethod);
  8. MethodBuilder removeMethod = tbClass.DefineMethod("remove_OnAuth", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, typeof(void), new Type[] { delegateBuilder });
  9. ILGenerator removeMethodIL = removeMethod.GetILGenerator();
  10. //......
  11. removeMethodIL.Emit(OpCodes.Ret);
  12. eb.SetRemoveOnMethod(removeMethod);
复制代码
留意事项:
1、定义变乱,通过特殊方法: DefineEvent 来定义。
2、定义变乱,第三个变乱参数Type,需要传递 delegateBuilder ,则不是 delegateType,否则会报错:

3、定义变乱,需要同时挂两个对应的添加和移除方法,否则,运行正常,但反编绎会报错:

4、定义方法,传递的委托类型,和留意事项2同等,需要传递 delegateBuilder,否则一样的错误信息。
下面查看正常情况下的反绎绎生成代码:

对委托和变乱的定义,一个神奇的Bug: 

通过反编绎 ILSpy 软件,可以看到已经定义成功了,但通过引用生成的程序集,即发现里面没有干系的委托或变乱产生?
同时通过 VS2022 自带的反编绎【直接F12跳转】,里面也没有任何干系的委托或变乱代码?

总结

构建类型是动态代码生成过程中的关键一环,通过机动运用 TypeBuilder 和干系工具,
我们可以实现各种复杂类型的动态生成,为程序的机动性和可扩展性提供有力支持。
总的来说,本章节通过演示如何使用 Emit 来动态创建类型,包括定义字段、方法、属性和变乱等,
资助读者理解如何在运行时生成和操作类型信息。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

愛在花開的季節

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表