Fireasy3 揭秘 — 使用 Emit 构建程序集

  • Fireasy3 揭秘 — 使用 Emit 构建程序集已关闭评论
  • 141 次浏览
  • A+
所属分类:.NET技术
摘要

  在运行期间,我们可以使用 Emit 来组织一段 IL 代码,进而动态生成一个方法,甚至是一个程序集(包括类型、方法或属性等等)。这个过程我们称之为动态编织。这一项技术应用比较广泛,比如数据映射(Dapper)、动态代理(AOP)等等,目的是提升大量反射而产生的性能问题。
  在 Fireasy 里,提供了以下几个构造器,用于生成一个完整的程序集:


目录

  • Fireasy3 揭秘 -- 依赖注入与服务发现
  • Fireasy3 揭秘 -- 自动服务部署
  • Fireasy3 揭秘 -- 使用 SourceGeneraor 改进服务发现
  • Fireasy3 揭秘 -- 使用 SourceGeneraor 实现动态代理(AOP)
  • Fireasy3 揭秘 -- 使用 Emit 构建程序集
  • Fireasy3 揭秘 -- 使用缓存提高反射性能
  • Fireasy3 揭秘 -- 动态类型及扩展支持
  • Fireasy3 揭秘 -- 线程数据共享的实现
  • Fireasy3 揭秘 -- 配置管理及解析处理
  • Fireasy3 揭秘 -- 数据库适配器
  • Fireasy3 揭秘 -- 解决数据库之间的语法差异
  • Fireasy3 揭秘 -- 获取数据库的架构信息
  • Fireasy3 揭秘 -- 数据批量插入的实现
  • Fireasy3 揭秘 -- 使用包装器对数据读取进行兼容
  • Fireasy3 揭秘 -- 数据行映射器
  • Fireasy3 揭秘 -- 数据转换器的实现
  • Fireasy3 揭秘 -- 通用序列生成器和雪花生成器的实现
  • Fireasy3 揭秘 -- 命令拦截器的实现
  • Fireasy3 揭秘 -- 数据库主从同步的实现
  • Fireasy3 揭秘 -- 大数据分页的策略
  • Fireasy3 揭秘 -- 数据按需更新及生成实体代理类
  • Fireasy3 揭秘 -- 用对象池技术管理上下文
  • Fireasy3 揭秘 -- Lambda 表达式解析的原理
  • Fireasy3 揭秘 -- 扩展选择的实现
  • Fireasy3 揭秘 -- 按需加载与惰性加载的区别与实现
  • Fireasy3 揭秘 -- 自定义函数的解析与绑定
  • Fireasy3 揭秘 -- 与 MongoDB 进行适配
  • Fireasy3 揭秘 -- 模块化的实现原理

  在运行期间,我们可以使用 Emit 来组织一段 IL 代码,进而动态生成一个方法,甚至是一个程序集(包括类型、方法或属性等等)。这个过程我们称之为动态编织。这一项技术应用比较广泛,比如数据映射(Dapper)、动态代理(AOP)等等,目的是提升大量反射而产生的性能问题。
  在 Fireasy 里,提供了以下几个构造器,用于生成一个完整的程序集:

  • DynamicAssemblyBuilder 动态程序集构造器
  • DynamicTypeBuilder 动态类型构造器
  • DynamicInterfaceBuilder 动态接口构造器
  • DynamicEnumBuilder 动态枚举构造器
  • DynamicFieldBuilder 动态字段域构造器
  • DynamicPropertyBuilder 动态属性构造器
  • DynamicConstructorBuilder 动态构造函数构造器
  • DynamicMethodBuilder 动态方法构造器

  接下来,我会对每个构造器进行介绍,以了解它们的基本原理。

DynamicAssemblyBuilder

  动态程序集构造器是一个起点,你只有先创建了一个程序集,才能在程序集里定义各种接口、类型。
  其实它的核心是在当前程序域内定义一个 AssemblyBuilder,再此基础上再定义一个 ModuleBuilder,这是程序集内部的结构,它们都来自于 System.Reflection.Emit 命名空间下。如下:

    public class DynamicAssemblyBuilder : DynamicBuilder     {         private AssemblyBuilder _assemblyBuilder;         private ModuleBuilder _moduleBuilder;          private AssemblyBuilder InitAssemblyBuilder()         {             if (_assemblyBuilder == null)             {                 var an = new AssemblyName(AssemblyName);                 if (string.IsNullOrEmpty(OutputAssembly))                 { #if NETFRAMEWORK                     _assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run); #else                     _assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndCollect); #endif                 }                 else                 { #if NETFRAMEWORK                     var dir = Path.GetDirectoryName(OutputAssembly);                     if (!Directory.Exists(dir))                     {                         Directory.CreateDirectory(dir);                     }                      _assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, dir); #else                     _assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run); #endif                 }             }              return _assemblyBuilder;         }          /// <summary>         /// 获取 <see cref="ModuleBuilder"/> 对象。         /// </summary>         /// <returns></returns>         private ModuleBuilder InitModuleBuilder()         {             if (_moduleBuilder == null)             {                 if (string.IsNullOrEmpty(OutputAssembly))                 {                     _moduleBuilder = AssemblyBuilder.DefineDynamicModule("Main");                 }                 else                 {                     var fileName = OutputAssembly.Substring(OutputAssembly.LastIndexOf("\") + 1); #if NETFRAMEWORK                     _moduleBuilder = AssemblyBuilder.DefineDynamicModule(fileName, fileName); #else                     _moduleBuilder = AssemblyBuilder.DefineDynamicModule(fileName); #endif                 }             }              return _moduleBuilder;         }     } 

  在 .net framework 时代,我们可以将动态构造的程序集存储到磁盘中,很遗憾,从 .net standard 之后就无法实现这一功能了,这给我们带来了诸多不便,因为动态生成的程序集必须存储在内存当中了。

  然后,DynamicAssemblyBuilder 提供了定义接口、类型和枚举的方法,将工作交给这些不同的构造器。如下:

        /// <summary>         /// 使用当前的构造器定义一个动态类型。         /// </summary>         /// <param name="typeName">类型的名称。</param>         /// <param name="accessibility">指定类的可见性。</param>         /// <param name="modifier">指定类的调用属性。</param>         /// <param name="baseType">类型的父类。</param>         /// <returns></returns>         public DynamicTypeBuilder DefineType(string typeName, Accessibility accessibility = Accessibility.Public, Modifier modifier = Modifier.Standard, Type baseType = null)         {             var typeBuilder = new DynamicTypeBuilder(Context, typeName, accessibility, modifier, baseType);             _typeBuilders.Add(typeBuilder);             return typeBuilder;         }          /// <summary>         /// 使用当前的构造器定义一个动态接口。         /// </summary>         /// <param name="typeName">类型的名称。</param>         /// <param name="accessibility">指定类的可见性。</param>         /// <returns></returns>         public DynamicInterfaceBuilder DefineInterface(string typeName, Accessibility accessibility = Accessibility.Public)         {             var typeBuilder = new DynamicInterfaceBuilder(Context, typeName, accessibility);             _typeBuilders.Add(typeBuilder);             return typeBuilder;         }          /// <summary>         /// 使用当前构造器定义一个枚举。         /// </summary>         /// <param name="enumName">枚举的名称。</param>         /// <param name="underlyingType">枚举的类型。</param>         /// <param name="accessibility">指定枚举的可见性。</param>         /// <returns></returns>         public DynamicEnumBuilder DefineEnum(string enumName, Type? underlyingType = null, Accessibility accessibility = Accessibility.Public)         {             var enumBuilder = new DynamicEnumBuilder(Context, enumName, underlyingType ?? typeof(int), accessibility);             _typeBuilders.Add(enumBuilder);             return enumBuilder;         } 

  所以 DynamicAssemblyBuilder 最多只能算是一个容器,更多的工作分解到各种构造器中。上面的方法中,定义接口、类型、枚举时,都将相应的构造器放到 _typeBuilders 集合里,在最后调用 Create 方法逐一创建。如下:

        /// <summary>         /// 创建程序集。         /// </summary>         /// <returns></returns>         public Assembly Create()         {             if (!_isCreated)             {                 foreach (var typeBuilder in _typeBuilders)                 {                     typeBuilder.CreateType();                 }                  _isCreated = true;             }              return AssemblyBuilder;         } 

DynamicTypeBuilder

  动态类型构造器是对 TypeBuilder 的包装。这里需要强调的是,在 DefineType 时,类的访问性由 Accessibility 枚举来指定,如 public、private、protected、internal 等等,修饰性则由 Modifier 枚举来指定,如 abstract、sealed。以下的方法主要用来设定类型的的 TypeAttributes,如下:

        private TypeAttributes GetTypeAttributes(Accessibility accessibility, Modifier modifier)         {             var attrs = GetTypeAttributes();             switch (modifier)             {                 case Modifier.Abstract:                     attrs |= TypeAttributes.Abstract;                     break;                 case Modifier.Sealed:                     attrs |= TypeAttributes.Sealed;                     break;             }              switch (accessibility)             {                 case Accessibility.Internal:                     if (_isNesetType)                     {                         attrs |= TypeAttributes.NestedAssembly;                     }                      break;                 case Accessibility.Private:                     if (_isNesetType)                     {                         attrs |= TypeAttributes.NestedPrivate;                     }                      break;                 case Accessibility.Public:                     attrs |= _isNesetType ? TypeAttributes.NestedPublic : TypeAttributes.Public;                     break;             }              return attrs;         } 

  这里重点要介绍一下泛型类型参数的处理。为了兼容定义方法时的泛型类型参数,这里定义了一个 GtpType 类型(Generic Type Parameter),它继承自 Type 类型,主要用到 Name 属性,其他属性均忽略。另外,通过以下的方法设定约束:

    /// <summary>     /// 用于标识一个泛型类型参数的类型。无法继承此类。     /// </summary>     public sealed class GtpType : Type     {         private Type? _baseType;         private Type[]? _constraintTypes;         private GenericParameterAttributes? _parameterAttributes;          /// <summary>         /// 设置基类约束。         /// </summary>         /// <param name="baseType">基类类型。</param>         /// <returns></returns>         public GtpType SetBaseTypeConstraint(Type baseType)         {             _baseType = baseType;             return this;         }          /// <summary>         /// 设置接口约束。         /// </summary>         /// <param name="constraintTypes">约束类型。</param>         /// <returns></returns>         public GtpType SetInterfaceConstraints(params Type[] constraintTypes)         {             _constraintTypes = constraintTypes;             return this;         }          /// <summary>         /// 设置参数特性。         /// </summary>         /// <param name="attributes"></param>         /// <returns></returns>         public GtpType SetGenericParameterAttributes(GenericParameterAttributes attributes)         {             _parameterAttributes = attributes;             return this;         }     } 

TypeBuilder 提供了一个方法 DefineGenericParameters 用于定义泛型类型参数。GtpTypeInitialize 方法是将基类约束、接口约束等设定到 GenericTypeParameterBuilder 对象里。如下:

        /// <summary>         /// 定义泛型参数。         /// </summary>         /// <param name="parameterTypes"></param>         /// <returns></returns>         public void DefineGenericParameters(params GtpType[] parameterTypes)         {             if (_genericParameterTypes != null)             {                 throw new InvalidOperationException("已经定义过泛型参数。");             }              _genericParameterTypes = parameterTypes.ToDictionary(s => s.Name);             var builders = _typeBuilder.DefineGenericParameters(parameterTypes.Select(s => s.Name).ToArray());              for (var i = 0; i < parameterTypes.Length; i++)             {                 parameterTypes[i].Initialize(builders[i]);             }         } 

  然后,DynamicTypeBuilder 提供了定义方法、构造函数、属性和嵌套类型的方法,将工作交给这些不同的构造器。如下:

        /// <summary>         /// 定义一个属性。         /// </summary>         /// <param name="propertyName">属性的名称。</param>         /// <param name="propertyType">属性的类型。</param>         /// <param name="accessibility">指定属性的可见性。</param>         /// <param name="modifier">指定属性的调用属性。</param>         /// <returns>新的 <see cref="DynamicPropertyBuilder"/>。</returns>         public virtual DynamicPropertyBuilder DefineProperty(string propertyName, Type propertyType, Accessibility accessibility = Accessibility.Public, Modifier modifier = Modifier.Standard)         {             return new DynamicPropertyBuilder(Context, propertyName, propertyType, accessibility, modifier);         }          /// <summary>         /// 定义一个方法。         /// </summary>         /// <param name="methodName">方法的名称。</param>         /// <param name="returnType">返回值的类型,如果为 void 则该参数为 null。</param>         /// <param name="parameterTypes">一个数组,表示方法的传入参数类型。</param>         /// <param name="accessibility">指定方法的可见性。</param>         /// <param name="modifier">指定方法的调用属性。</param>         /// <param name="ilCoding">方法体的 IL 过程。</param>         /// <returns>新的 <see cref="DynamicMethodBuilder"/>。</returns>         public virtual DynamicMethodBuilder DefineMethod(string methodName, Type? returnType = null, Type[]? parameterTypes = null, Accessibility accessibility = Accessibility.Public, Modifier modifier = Modifier.Standard, Action<BuildContext> ilCoding = null)         {             return new DynamicMethodBuilder(Context, methodName, returnType, parameterTypes, accessibility, modifier, ilCoding);         }          /// <summary>         /// 定义一个构造函数。         /// </summary>         /// <param name="parameterTypes"></param>         /// <param name="accessibility"></param>         /// <param name="modifier"></param>         /// <param name="ilCoding"></param>         /// <returns></returns>         public virtual DynamicConstructorBuilder DefineConstructor(Type[] parameterTypes, Accessibility accessibility = Accessibility.Public, Modifier modifier = Modifier.Standard, Action<BuildContext> ilCoding = null)         {             return new DynamicConstructorBuilder(Context, parameterTypes, accessibility, modifier, ilCoding);         }          /// <summary>         /// 定义一个字段。         /// </summary>         /// <param name="fieldName">字段的名称。</param>         /// <param name="fieldType">字段的类型。</param>         /// <param name="defaultValue">默认值。</param>         /// <param name="accessibility"></param>         /// <param name="modifier"></param>         /// <returns></returns>         public virtual DynamicFieldBuilder DefineField(string fieldName, Type fieldType, object? defaultValue = null, Accessibility accessibility = Accessibility.Private, Modifier modifier = Modifier.Standard)         {             return new DynamicFieldBuilder(Context, fieldName, fieldType, defaultValue, accessibility, modifier);         }          /// <summary>         /// 定义一个嵌套的类型。         /// </summary>         /// <param name="typeName"></param>         /// <param name="accessibility"></param>         /// <param name="baseType"></param>         /// <returns></returns>         public virtual DynamicTypeBuilder DefineNestedType(string typeName, Accessibility accessibility = Accessibility.Private, Type? baseType = null)         {             var nestedType = new DynamicTypeBuilder(Context, typeName, accessibility, baseType);             _nestedTypeBuilders.Add(nestedType);             return nestedType;         }          /// <summary>         /// 使用当前的构造器定义一个动态接口。         /// </summary>         /// <param name="typeName">类型的名称。</param>         /// <param name="accessibility">指定类的可见性。</param>         /// <returns></returns>         public DynamicInterfaceBuilder DefineNestedInterface(string typeName, Accessibility accessibility = Accessibility.Public)         {             var typeBuilder = new DynamicInterfaceBuilder(Context, typeName, accessibility);             _nestedTypeBuilders.Add(typeBuilder);             return typeBuilder;         }          /// <summary>         /// 使用当前构造器定义一个枚举。         /// </summary>         /// <param name="enumName">枚举的名称。</param>         /// <param name="underlyingType">枚举的类型。</param>         /// <param name="accessibility">指定枚举的可见性。</param>         /// <returns></returns>         public DynamicEnumBuilder DefineNestedEnum(string enumName, Type? underlyingType = null, Accessibility accessibility = Accessibility.Public)         {             var enumBuilder = new DynamicEnumBuilder(Context, enumName, underlyingType ?? typeof(int), accessibility);             _nestedTypeBuilders.Add(enumBuilder);             return enumBuilder;         } 

DynamicMethodBuilder

  动态方法构造器在定义时,需要指定参数类型,返回类型等等,对于泛型方法,也需要使用 GtpType 类型来定义。以下的方法是用于处理泛型方法的:

        private void ProcessGenericMethod()         {             Dictionary<string, GenericTypeParameterBuilder>? builders = null;              //方法参数里有泛型类型参数             if (ParameterTypes?.Any(s => s is GtpType) == true)             {                 //筛选没有在类型构造器里定义过的泛型类型参数                 var names = ParameterTypes.Where(s => s is GtpType).Where(s => !Context.TypeBuilder.TryGetGenericParameterType(s.Name, out _)).Cast<GtpType>().Select(s => s.Name).ToArray();                  //如果有新的泛型类型参数,则在方法构造器里定义                 if (names.Length > 0)                 {                      builders = _methodBuilder.DefineGenericParameters(names).ToDictionary(s => s.Name);                 }                  for (var i = 0; i < ParameterTypes.Length; i++)                 {                     if (ParameterTypes[i] is GtpType gt)                     {                         if (builders?.TryGetValue(gt.Name, out var parb) == true)                         {                             ParameterTypes[i] = gt.Initialize(parb);                         }                         else if (Context.TypeBuilder.TryGetGenericParameterType(gt.Name, out var gt1))                         {                             ParameterTypes[i] = gt1.GenericTypeParameterBuilder;                         }                     }                 }                  MethodBuilder.SetParameters(ParameterTypes);             }              //如果返回类型是泛型类型             if (ReturnType is GtpType rgt)             {                 //先在方法构造器里查找                 if (builders?.TryGetValue(rgt.Name, out var retb) == true)                 {                     ReturnType = rgt.Initialize(retb);                 }                 //在类型构造器里查找                 else if (Context.TypeBuilder.TryGetGenericParameterType(rgt.Name, out var gt1))                 {                     ReturnType = gt1.GenericTypeParameterBuilder;                 }             }         } 

  这样,就完美处理了泛型方法,文章最后会例举测试用例进一步加深印象。
  如果动态类型指定了所继承的基类,还需要处理重载方法,以下的方法用于在父类中查找与名称和参数相匹配的方法:

        private MethodInfo? FindMethod(string methodName, IEnumerable<Type> parameterTypes)         {             MethodInfo? method = null;             if (Context.TypeBuilder.BaseType != null)             {                 method = Helper.MatchMethod(Context.TypeBuilder.BaseType, methodName, parameterTypes);                  if (method != null && !method.IsVirtual)                 {                     throw new DynamicBuildException("所定义的方法在父类中未标记 virtual、abstract 或 override。");                 }             }              //在实现的接口中查找方法             var interfaceTypes = Context.TypeBuilder.InterfaceTypes                 .Union(Context.TypeBuilder.InterfaceTypes.SelectMany(s => s.GetInterfaces()))                 .Distinct().ToList();              //在实现接口中去查找方法             if (method == null && interfaceTypes.Count != 0)             {                 foreach (var type in interfaceTypes)                 {                     method = type.GetMethod(methodName, parameterTypes == null ? Type.EmptyTypes : parameterTypes.ToArray());                     if (method != null)                     {                         break;                     }                 }             }              return method;         } 

  在处理 MethodAttributes 时,如果匹配到父类的方法,则也会有不同的处理,这些属性的含义,需要自己去慢慢理解。如下:

        private MethodAttributes GetMethodAttributes(string methodName, IEnumerable<Type> parameterTypes, Accessibility accessibility, Modifier modifier)         {             var method = FindMethod(methodName, parameterTypes);             var isOverride = method != null && method.IsVirtual;             var isInterface = isOverride && method!.DeclaringType!.IsInterface;             var isBaseType = isOverride && method!.DeclaringType == Context.TypeBuilder.BaseType;             if (method != null)             {                 Context.BaseMethod = method;             }              var attrs = GetMethodAttributes(accessibility, modifier);             if (isOverride)             {                 attrs |= MethodAttributes.Virtual;                  //去掉 NewSlot                 if (isBaseType && _attributes.HasFlag(MethodAttributes.NewSlot))                 {                     attrs &= ~MethodAttributes.NewSlot;                 }                 else if (isInterface)                 {                     //如果没有传入 modifier,则加 Final 去除上面定义的 Virtual                     if (modifier == Modifier.Standard)                     {                         attrs |= MethodAttributes.Final;                     }                      attrs |= MethodAttributes.NewSlot;                 }             }             else if (method != null)             {             }              return attrs;         } 

  在 DefineMethod 方法中,最后一个参数 ilCoding 允许你用 IL 指令编写一段代码,以作为方法体。Emitter 属性是一个 EmitHelper 对象,它是对 ILGenerator 对象的包装,可以更方便地使用链式语法编写 IL 指令。从构造函数里调用 InitBuilder 方法可以看出它的工作原理:

        private void InitBuilder()         {             //此处略去             Context.Emitter = new EmitHelper(_methodBuilder.GetILGenerator(), _methodBuilder);             //此处略去             if (_buildAction != null)             {                 _buildAction(Context);             }             else             {                 Context.Emitter.ret();             }         } 

  通过 DefineMethod 方法编写 IL 指令后,还可以使用 OverwriteCode 方法进行覆盖,或使用 AppendCode 方法进行追加,如下:

        /// <summary>         /// 追加新的 MSIL 代码到构造器中。         /// </summary>         /// <param name="ilCoding"></param>         /// <returns></returns>         public DynamicMethodBuilder AppendCode(Action<EmitHelper> ilCoding)         {             ilCoding?.Invoke(Context.Emitter);              return this;         }          /// <summary>         /// 使用新的 MSIL 代码覆盖构造器中的现有代码。         /// </summary>         /// <param name="ilCoding"></param>         /// <returns></returns>         public DynamicMethodBuilder OverwriteCode(Action<EmitHelper> ilCoding)         {             var field = typeof(MethodBuilder).GetField("m_ilGenerator", BindingFlags.NonPublic | BindingFlags.Instance);             if (field != null)             {                 var cons = typeof(ILGenerator).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];                 field.SetValue(_methodBuilder, cons.Invoke(new[] { _methodBuilder }));                 Context.Emitter = new EmitHelper(_methodBuilder.GetILGenerator(), _methodBuilder);             }              return AppendCode(ilCoding);         } 

DynamicPropertyBuilder

  动态属性构造器就要容易一些,只需要用它来定义 get 和 set 方法,它一般是自动属性的,如果要使用到字段域,则传入字段域构造器即可。如果你的 get 或 set 方法很复杂,那就使用 ilCoding 进行指令编码。如下:

        /// <summary>         /// 获取当前的 <see cref="DynamicFieldBuilder"/>。         /// </summary>         /// <returns></returns>         public DynamicFieldBuilder FieldBuilder         {             get             {                 return _fieldBuilder ?? (_fieldBuilder = Context.TypeBuilder.DefineField(string.Format("m_<{0}>", Name), PropertyType));             }         }          /// <summary>         /// 定义属性的 Get 访问方法。         /// </summary>         /// <param name="accessibility">指定方法的可见性。</param>         /// <param name="modifier">指定方法的调用属性。</param>         /// <param name="ilCoding">方法体的 IL 过程。</param>         /// <returns>新的 <see cref="DynamicMethodBuilder"/>。</returns>         public DynamicMethodBuilder DefineGetMethod(Accessibility accessibility = Accessibility.Public, Modifier modifier = Modifier.Standard, Action<BuildContext> ilCoding = null)         {             var isInterface = Context.TypeBuilder is DynamicInterfaceBuilder;             var method = new DynamicMethodBuilder(Context, string.Concat("get_", GetMethodName()), PropertyType, Type.EmptyTypes, accessibility, modifier, ctx =>                 {                     if (isInterface)                     {                         return;                     }                      if (ilCoding != null)                     {                         ilCoding(ctx);                     }                     else                     {                         ctx.Emitter.ldarg_0.ldfld(FieldBuilder.FieldBuilder).ret();                     }                 });             PropertyBuilder.SetGetMethod(method.MethodBuilder);             return method;         }          /// <summary>         /// 定义属性的 Get 访问方法。         /// </summary>         /// <param name="accessibility">指定方法的可见性。</param>         /// <param name="modifier">指定方法的调用属性。</param>         /// <param name="fieldBuilder">指定一个属性相关的 <see cref="DynamicFieldBuilder"/>。</param>         /// <returns>新的 <see cref="DynamicMethodBuilder"/>。</returns>         public DynamicMethodBuilder DefineGetMethodByField(Accessibility accessibility = Accessibility.Public, Modifier modifier = Modifier.Standard, DynamicFieldBuilder? fieldBuilder = null)         {             var isInterface = Context.TypeBuilder is DynamicInterfaceBuilder;             var method = new DynamicMethodBuilder(Context, string.Concat("get_", GetMethodName()), PropertyType, Type.EmptyTypes, accessibility, modifier, ctx =>                 {                     if (isInterface)                     {                         return;                     }                      fieldBuilder ??= FieldBuilder;                      ctx.Emitter.ldarg_0.ldfld(fieldBuilder.FieldBuilder).ret();                 });              PropertyBuilder.SetGetMethod(method.MethodBuilder);             return method;         } 

DynamicConstructorBuilder

动态构造函数构造器,如果类型继承了基类,则默认的方法体需要调用父类构造函数。如下:

        internal DynamicConstructorBuilder(BuildContext context, Type[] parameterTypes, Accessibility accessibility = Accessibility.Public, Modifier modifier = Modifier.Standard, Action<BuildContext> ilCoding = null)             : base(accessibility, modifier)         {             Context = new BuildContext(context) { ConstructorBuilder = this };             ParameterTypes = parameterTypes;              if (ilCoding == null)             {                 if (context.TypeBuilder.BaseType != typeof(object))                 {                     var constructor = Helper.MatchConstructor(Context.TypeBuilder.BaseType, parameterTypes);                      if (constructor != null)                     {                         ilCoding = c => c.Emitter.ldarg_0                             .If(parameterTypes != null, b => b.For(0, parameterTypes!.Length, (e, i) => e.ldarg(i + 1)))                             .call(constructor).ret();                     }                 }             }              ilCoding ??= c => c.Emitter.ret();              _buildAction = ilCoding;             _attributes = GetMethodAttributes(accessibility, modifier);             InitBuilder();         } 

  最后,说一下关于自定义特性。在构造器基类 DynamicBuilder 里,有一个 SetCustomAttribute 方法,它可以使用 lambda 表达式来指定自定义特性。

测试用例

  创建一个类型,继承基类,实现接口:

        [TestMethod]         public void TestTypeBuilder()         {             /*             public class MyClass : MyBaseClass, IMyInterface             {                 public string Title { get; set; }                 public void HelloWorld()                 {                 }                 public void WriteName(string a1, string a2)                 {                 }             }             */              var assemblyBuilder = new DynamicAssemblyBuilder("MyAssembly");             var typeBuilder = assemblyBuilder.DefineType("MyClass");              typeBuilder.BaseType = typeof(MyBaseClass);              typeBuilder.ImplementInterface(typeof(IMyInterface));              var methodBuilder = typeBuilder.DefineMethod("HelloWorld");             var propertyBuilder = typeBuilder.DefineProperty("Title", typeof(string)).DefineGetSetMethods();              methodBuilder = typeBuilder.DefineMethod("WriteName", typeof(string), new[] { typeof(string) });              var type = typeBuilder.CreateType();              Assert.IsTrue(typeof(IMyInterface).IsAssignableFrom(type));         } 

  创建一个泛型类型,以及泛型方法:

        [TestMethod]         public void TestDefineGenericType()         {             /*             public class MyClass<T, TS> where T : MyBaseClass             {                 public MyClass(TS ts)                 {                 }                 public T Hello<TV>(T t, TV tv)                 {                     Console.WriteLine(tv);                     return t;                 }             }             */              var gt = new GtpType("T").SetBaseTypeConstraint(typeof(MyBaseClass));              var assemblyBuilder = new DynamicAssemblyBuilder("MyAssembly");             var typeBuilder = assemblyBuilder.DefineType("MyClass");             //定义泛型类型参数             typeBuilder.DefineGenericParameters(gt, new GtpType("TS"));              //定义构造函数             typeBuilder.DefineConstructor(new Type[] { new GtpType("TS") });              //定义一个泛型方法,TV不在类中定义,所以属于方法的泛型类型参数             var methodBuilder = typeBuilder.DefineMethod("Hello", gt, new Type[] { gt, new GtpType("TV") }, ilCoding: c =>             {                 c.Emitter                 .ldarg_2.call(typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }))                 .ldarg_1.ret();             });              var type = typeBuilder.CreateType().MakeGenericType(typeof(MyBaseClass), typeof(int));             var obj = Activator.CreateInstance(type, 100);              var method = type.GetMethod("Hello").MakeGenericMethod(typeof(string));             var value = method.Invoke(obj, new object[] { new MyBaseClass(), "world" });              Assert.IsInstanceOfType(value, typeof(MyBaseClass));         } 

  定义泛型方法:

        /// <summary>         /// 使用泛型参数测试DefineMethod方法。         /// </summary>         [TestMethod()]         public void TestDefineGenericMethod()         {             var typeBuilder = CreateBuilder();              /*             public class testClass             {                 public void Hello<T1, T2>(string name, T1 any1, T2 any2)                 {                     Console.Write(name + any1 + any2);                 }             }             */             var methodBuilder = typeBuilder.DefineMethod("Hello", parameterTypes: new Type[] { typeof(string), new GtpType("T1"), new GtpType("T2") });             methodBuilder.DefineParameter("name");             methodBuilder.DefineParameter("any1");             methodBuilder.DefineParameter("any2");              var paraCount = methodBuilder.ParameterTypes.Length;              methodBuilder.OverwriteCode(e =>             {                 e.ldc_i4(paraCount)                 .newarr(typeof(object))                 .dup.ldc_i4_0.ldarg_1.stelem_ref                 .For(1, paraCount, (e1, i) =>                 {                     e1.dup.ldc_i4(i).ldarg(i + 1).box(methodBuilder.ParameterTypes[i]).stelem_ref.end();                 })                 .call(typeof(string).GetMethod("Concat", new[] { typeof(object[]) }))                 .call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }))                 .ret();             });              var type = typeBuilder.CreateType();              var method = type.GetMethod("Hello");             Assert.IsNotNull(method);             Assert.IsTrue(method.IsGenericMethod);              var obj = Activator.CreateInstance(type);              method = method.MakeGenericMethod(typeof(int), typeof(decimal));              method.Invoke(obj, new object[] { "fireasy", 22, 45m });         } 

  显式实现方法:

        /// <summary>         /// 使用接口成员显式实现测试ImplementInterface方法。         /// </summary>         [TestMethod()]         public void ImplementInterfaceWithExplicitMember()         {             /*             public class testClass : IDynamicMethodInterface             {                 void IDynamicMethodInterface.Test(int s)                 {                     Console.WriteLine(s);                 }             }             */             var typeBuilder = CreateBuilder();              typeBuilder.ImplementInterface(typeof(IDynamicMethodInterface));             var methodBuilder = typeBuilder.DefineMethod("Test",                 parameterTypes: new[] { typeof(int) },                 modifier: Modifier.ExplicitImpl,                 ilCoding: (e) => e.Emitter.ldstr("fireasy").call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) })).ret());              methodBuilder.DefineParameter("s");              var type = typeBuilder.CreateType();              var obj = Activator.CreateInstance(type) as IDynamicMethodInterface;             obj.Test(111);              Assert.IsTrue(typeof(IDynamicMethodInterface).IsAssignableFrom(type));         } 

  继承泛型基类,并且定义构造函数:

        /// <summary>         /// 测试DefineConstructor方法。         /// </summary>         [TestMethod()]         public void TestDefineConstructorForGeneric()         {             var typeBuilder = CreateBuilder();              /*             public class testClass<T> : GenericClass<T>             {                 public testClass(T value)                     : base (value)                 {                 }             }             */              var gtp = new GtpType("T");             typeBuilder.BaseType = typeof(GenericClass<>);             typeBuilder.DefineGenericParameters(gtp);              var constructorBuilder = typeBuilder.DefineConstructor(new Type[] { gtp });             constructorBuilder.DefineParameter("value");              var type = typeBuilder.CreateType();              type = type.MakeGenericType(typeof(string));              var obj = Activator.CreateInstance(type, new[] { "fireasy" });             Assert.IsNotNull(obj);          } 

  最后,奉上 Fireasy 3 的开源地址:https://gitee.com/faib920/fireasy3 ,欢迎大家前来捧场。

  本文相关代码请参考:
  https://gitee.com/faib920/fireasy3/src/libraries/Fireasy.Common/Emit
  https://gitee.com/faib920/fireasy3/tests/Fireasy.Common.Tests/EmitTests.cs

  更多内容请移步官网 http://www.fireasy.cn 。