- A+
目录
- 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
用于定义泛型类型参数。GtpType
的 Initialize
方法是将基类约束、接口约束等设定到 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 。