基于CodeGenerator的Emit代码生成辅助类源码及演示

本文介绍了一组基于Emit动态生成代码的辅助类,包括CodeGenerator和DynamicMethodFactory。CodeGenerator封装了Emit方法,简化了操作逻辑。DynamicMethodFactory实现了第三方程序集内部类的实例化,以及通过DynamicMethod高效访问泛型方法。
Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

本文介绍一组NBearV4中的基于Emit动态生成代码的辅助类,部分概念在本人的blog之前的文章中或多或少都有介绍,这里包含最新的更新及演示、测试。主要是两个类:CodeGenerator和 DynamicMethodFactory。前者提供了一种经过封装的,简化Emit方法(包括Emit DynamicMethod,Constructor,Method,get、set Method of Property)的方案;后者基于前者,实现了一种访问指定类(可以是第三方程序集的internal类)的方法或成员变量,实例化第三方程序集中的internal类型,高性能的以非泛型语法访问泛型方法的机制(通过DynamicMethod和Delegate实现)。

下载源码:NBear.Common.zip

介绍

CodeGenerator

该类很多地方参照了.NET 3.0的System.Runtime.Serialization.dll中的同名internal类,他封装了Emit中的各种Emit层面的常用操作逻辑,包括Ld各种value、成员变量,if-else,case switch,loop等分支控制等,扩展的版本使用DesignByContract对所有的输入参数进行了检查,并扩展了对Emit Constructor,Method,get、set Method of Property的支持。

关于Emit DynamicMethod的示例,大家可以参见稍后介绍的DynamicMethodFactory类,这里先给出一个使用该类Emit一个类,并实现一个接口的示例代码,该示例代码为包含于源码的CodeGenerator.cs文件末尾的UnitTest代码:

 1      namespace  CodeGeneratorUnitTest
 2      {
 3        public interface ITest
 4        {
 5            string Wow(string str);
 6        }

 7
 8        public class UnitTest
 9        {
10            public static void TestEmitInterface()
11            {
12                AssemblyName assName = new AssemblyName("TestEmitInterface");
13                AssemblyBuilder assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
14                ModuleBuilder modBuilder = assBuilder.DefineDynamicModule(assBuilder.GetName().Name);
15                TypeBuilder typeBuilder = modBuilder.DefineType("TestEmitInterface.TestImpl", TypeAttributes.Public);
16                typeBuilder.AddInterfaceImplementation(typeof(ITest));
17
18                CodeGenerator ctor = new CodeGenerator(typeBuilder, "ctor", MethodAttributes.Public, CallingConventions.Standard, null, Type.EmptyTypes);
19                ctor.Ldarg(0);
20                ctor.Call(typeof(object).GetConstructor(Type.EmptyTypes));
21                ctor.Ret();
22
23                MethodInfo mi = typeof(ITest).GetMethod("Wow");
24
25                CodeGenerator wow = new CodeGenerator(typeBuilder, mi.Name, mi.Attributes & (~MethodAttributes.Abstract) | MethodAttributes.Public, mi.CallingConvention, mi.ReturnType, new Type[] typeof(string) });
26                wow.Ldarg(1);
27                wow.Ret();
28
29                typeBuilder.DefineMethodOverride(wow.CurrentMethod, mi);
30
31                Type testImplType = typeBuilder.CreateType();
32                ITest test = (ITest)Activator.CreateInstance(testImplType);
33                Check.Assert(test.Wow("hello"== "hello");
34            }

35        }

36    }

以上代码Emit了一个TestImpl类,它实现了ITest接口,包含一个默认构造函数和一个Wow方法,注意,构造函数和方法都是通过CodeGenerator Emit的,这里的逻辑比较简单,但应该已经能看到相对于ilGen.Emit(OpCodes.XXX, YYY)这样的语法的简化,如果实现逻辑复杂,对整个Emit过程的简化就更明显。

DynamicMethodFactory

该类的主要功能包括:实例化第三方程序集中的internal类型(DynamicMethodFactory.CreateInstance()方法),为指定类型(可以是第三方程序集中的internal类型)的泛型或非泛型方法、属性、字段的读写生成非强类型的Delegate(通过DynamicMethod实现,不使用反射,性能接近直接访问)。

下面先给出一个该类中为一个Method创建一个DynamicMethod,并返回其Delegate的示例,DynamicMethod是使用前面介绍的CodeGenerator实现的:

 1          protected   static  DynamicMethodProxyHandler DoGetMethodDelegate(
 2             Module targetModule,
 3             MethodInfo genericMethodInfo,
 4              params  Type[] genericParameterTypes)
 5          {
 6            Check preconditions
16
17            //Create a dynamic method proxy delegate used to call the specified methodinfo
18            CodeGenerator gen = new CodeGenerator(targetModule);
19            gen.BeginMethod("dm" + Guid.NewGuid().ToString("N"), typeof(DynamicMethodProxyHandler));
20            MethodInfo makeGenericMethodInfo = MakeMethodGeneric(genericMethodInfo, genericParameterTypes);
21            gen.Ldarg(0);
22            LoadParameters(gen, makeGenericMethodInfo.GetParameters(), false);
23            gen.Call(makeGenericMethodInfo);
24            CastValueToObject(gen, makeGenericMethodInfo.ReturnType);
25
26            return (DynamicMethodProxyHandler)gen.EndMethod();
27        }

LoadParameters和CastValueToObject的代码

代码是不是相对比较简单呢(当然是相对于自己写所有的Emit来讲的),注意这里的LoadParameter方法的实现您可以发现,为方法生成调用Delegate是完美支持输入输出参数的。

下面给出
DynamicMethodFactory类的UnitTest代码,演示了对方法、字段和属性的生成Delegate和基于Delegate的读写,且包括对输入输出参数的使用:

  1      namespace  DynamicMethodFactoryUnitTest
  2      {
  3        public class TestClass
  4        {
  5            public static void StaticReturnVoidMethod()
  6            {
  7            }

  8
  9            public static int StaticReturnIntMethod(string str, int i, ref int refInt, ref string refStr)
 10            {
 11                Check.Assert(str == "str");
 12                Check.Assert(i == 1);
 13                Check.Assert(refInt == 3);
 14                Check.Assert(refStr == "instr");
 15
 16                int ret = i + refInt;
 17                refInt = i + 1;
 18                refStr = "ref" + str;
 19
 20                Check.Assert(refInt == 2);
 21                Check.Assert(ret == 4);
 22                Check.Assert(refStr == "refstr");
 23
 24                return ret;
 25            }

 26
 27            public static int StaticIntField;
 28
 29            public static int StaticIntProperty
 30            {
 31                get
 32                {
 33                    return StaticIntField;
 34                }

 35                set
 36                {
 37                    StaticIntField = value;
 38                }

 39            }

 40
 41            public void NonStaticReturnVoidMethod()
 42            {
 43            }

 44
 45            public int NonStaticReturnIntMethod(string str, int i, out int outInt, out string outStr)
 46            {
 47                outInt = i + 1;
 48                Check.Assert(outInt == 2);
 49                outStr = "out" + str;
 50                Check.Assert(outStr == "outstr");
 51                return i + 2;
 52            }

 53
 54            public int NonStaticIntField;
 55
 56            public int NonStaticIntProperty
 57            {
 58                get
 59                {
 60                    return NonStaticIntField;
 61                }

 62                set
 63                {
 64                    NonStaticIntField = value;
 65                }

 66            }

 67        }

 68
 69        public class UnitTest
 70        {
 71            private static DynamicMethodFactory fac = new DynamicMethodFactory();
 72
 73            public static void TestStaticMethod()
 74            {
 75                StaticDynamicMethodProxyHandler handler = fac.GetStaticMethodDelegate(typeof(TestClass).GetMethod("StaticReturnVoidMethod"));
 76                handler(null);
 77
 78                object[] inputParams = new object[] "str"13"instr" };
 79                handler = fac.GetStaticMethodDelegate(typeof(TestClass).GetMethod("StaticReturnIntMethod"));
 80                object ret = handler(inputParams);
 81                Check.Assert(((int)inputParams[2]) == 2);
 82                Check.Assert(((string)inputParams[3]) == "refstr");
 83                Check.Assert(((int)ret) == 4);
 84            }

 85
 86            public static void TestStaticField()
 87            {
 88                TestClass.StaticIntField = -1;
 89                FieldInfo field = typeof(TestClass).GetField("StaticIntField"); ;
 90                StaticDynamicMethodProxyHandler handler = fac.GetStaticFieldSetDelegate(field);
 91                handler(new object[] 5 });
 92                Check.Assert(TestClass.StaticIntField == 5);
 93                handler = fac.GetStaticFieldGetDelegate(field);
 94                Check.Assert(((int)handler(null)) == 5);
 95            }

 96
 97            public static void TestStaticProperty()
 98            {
 99                TestClass.StaticIntField = -1;
100                PropertyInfo property = typeof(TestClass).GetProperty("StaticIntProperty"); ;
101                StaticDynamicMethodProxyHandler handler = fac.GetStaticMethodDelegate(property.GetSetMethod());
102                handler(new object[] 5 });
103                Check.Assert(TestClass.StaticIntProperty == 5);
104                handler = fac.GetStaticMethodDelegate(property.GetGetMethod());
105                Check.Assert(((int)handler(null)) == 5);
106            }

107
108            public static void TestNonStaticMethod()
109            {
110                TestClass obj = new TestClass();
111
112                DynamicMethodProxyHandler handler = fac.GetMethodDelegate(typeof(TestClass).GetMethod("NonStaticReturnVoidMethod"));
113                handler(obj, null);
114
115                object[] inputParams = new object[] "str"1nullnull };
116                handler = fac.GetMethodDelegate(typeof(TestClass).GetMethod("NonStaticReturnIntMethod"));
117                object ret = handler(obj, inputParams);
118                Check.Assert(((int)inputParams[2]) == 2);
119                Check.Assert(((string)inputParams[3]) == "outstr");
120                Check.Assert(((int)ret) == 3);
121            }

122
123            public static void TestNonStaticField()
124            {
125                TestClass obj = new TestClass();
126                obj.NonStaticIntField = -1;
127
128                FieldInfo field = typeof(TestClass).GetField("NonStaticIntField"); ;
129                DynamicMethodProxyHandler handler = fac.GetFieldSetDelegate(field);
130                handler(obj, new object[] 5 });
131                Check.Assert(obj.NonStaticIntField == 5);
132                handler = fac.GetFieldGetDelegate(field);
133                Check.Assert(((int)handler(obj, null)) == 5);
134            }

135
136            public static void TestNonStaticProperty()
137            {
138                TestClass obj = new TestClass();
139                obj.NonStaticIntField = -1;
140
141                PropertyInfo property = typeof(TestClass).GetProperty("NonStaticIntProperty"); ;
142                DynamicMethodProxyHandler handler = fac.GetMethodDelegate(property.GetSetMethod());
143                handler(obj, new object[] 5 });
144                Check.Assert(obj.NonStaticIntField == 5);
145                handler = fac.GetMethodDelegate(property.GetGetMethod());
146                Check.Assert(((int)handler(obj, null)) == 5);
147            }

148        }

149    }

DynamicMethodFactory类还可以用于以非泛型方法的调用语法调用泛型方法,在之前的一篇文章介绍过,这里就不重复了,感兴趣的朋友可以参见:改进的以非泛型方式调用泛型方法”之基于DynamicMethod的实现

有任何问题欢迎回复讨论。

//The End

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

对象关系映射架构(DBFramework)及代码生成源码 一、使用对象关系映射组件Kenly.DBFramework.dll不用编写任何SQL或者存储过程即可实现下列功能: 1、数据表、视图和存储过程与对象之间的转换。 2、数据表、视图的自定义条件查询。 3、数据表、视图的分页查询。 4、根据ID、主键或自定义条件对数据表进行增、删、改操作。 5、实现一对一、一对多、多对一和多对多的关系映射。 6、支持单个对象和多个对象之间的事务控制。 7、支持查询结果排序。 8、支持查询表达式生成。 9、支持延迟加载。 二、代码生成器 1、根据指定的数据库连接,自动生成数据表、视图和存储过程对应的对象代码(C#代码)。 2、自动生成相关的工程文件,生成完整的业务层项目文件。 3、可以帮助生成自定义查询方法。 4、支持SQLServer2000、SQLServer2005和Oracle代码生成插件,支持插件扩展。 提供 1、对象关系映射组件: Kenly.DBFramework.dll 2、代码生成源码:CodeHelper。 3、代码生成器插件源码(支持SQLServer2000、SQLServer2005和Oracle):Plugin。 4、使用手册:DBFramework.Manual V4.5.3.pdf。 主要API: public abstract class ViewGateway where T: new() { // Methods static ViewGateway(); protected ViewGateway(); protected static int Count(); protected static int Count(string condition); protected static List CountGroup(string groupBy); protected static List CountGroup(string condition, string groupBy); public static List CreateInstances(int count); protected static List Distinct(string columnName); protected static List Distinct(string columnName, string condition); protected static List Distinct(string columnName, string condition, bool ignoreNull); protected static bool Exists(string condition); public bool ExistsById(); public bool ExistsByPK(); protected static List Find(PagingArg pagingArg, params string[] propertyNames); protected static List Find(string condition, params string[] propertyNames); protected static List Find(PagingArg pagingArg, bool sqlServer2000, params string[] propertyNames); protected static List Find(string condition, PagingArg pagingArg, params string[] propertyNames); protected static List Find(string condition, PagingArg pagingArg, bool sqlServer2000, params string[] propertyNames); protected static List FindAll(params string[] propertyNames); protected static void FindTop(T firstOne); protected static List FindTop(int topCount, params string[] propertyNames); protected static void FindTop(string condition, T firstOne); protected static List FindTop(string condition, int topCount, params string[] propertyNames); protected static void InitializeGateway(GatewayConfig config); protected static void InitializeGateway(DatabaseType dbType, string connectionString); protected void InitializeInstance(T entity); protected static object Max(string columnName); protected static object Max(string columnName, string condition); protected static List MaxGroup(string columnName, string groupBy); protected static List MaxGroup(string columnName, string condition, string groupBy); protected static object Min(string columnName); protected static object Min(string columnName, string condition); protected static List MinGroup(string columnName, string groupBy); protected static List MinGroup(string columnName, string condition, string groupBy); protected static DataTable Query(PagingArg pagingArg, params string[] propertyNames); protected static DataTable Query(string condition, params string[] propertyNames); protected static DataTable Query(PagingArg pagingArg, bool sqlServer2000, params string[] propertyNames); protected static DataTable Query(string condition, PagingArg pagingArg, params string[] propertyNames); protected static DataTable Query(string condition, PagingArg pagingArg, bool sqlServer2000, params string[] propertyNames); protected static DataTable QueryAll(params string[] propertyNames); protected static DataTable QueryTop(int topCount, params string[] propertyNames); protected static DataTable QueryTop(string condition, int topCount, params string[] propertyNames); public ArrayList RetrieveAssociations(); public ArrayList RetrieveAssociations(Type elementType); public ArrayList RetrieveAssociations(params Type[] elementTypes); public void RetrieveById(); public void RetrieveByPK(); protected internal virtual void RetrieveBySql(string sql); public void ShadowCopyTo(object targetEntity); public void ShadowCopyTo(T targetEntity); protected static double Sum(string columnName); protected static double Sum(string columnName, string condition); protected static List SumGroup(string columnName, string groupBy); protected static List SumGroup(string columnName, string condition, string groupBy); public static string ToColumnName(string propertyName); public static T ToObject(DataRow adaptedRow); public static List ToObjects(DataTable adaptedTable); public static List ToObjects(DataRow[] adaptedRows); public static string ToPropertyName(string columnName); public static DataTable ToTable(IList entities); public static DataTable ToTable(params T[] entities); public static DataTable ToTable(bool isAdapted, params T[] entities); public static DataTable ToTable(bool isAdapted, IList entities); // Properties protected internal static string CommandText { get; } protected internal static GatewayConfig Config { get; } internal T Entity { get; set; } public object EntityId { get; } public object PrimaryKey { get; } protected static Order SortedOrder { get; set; } } public abstract class TableGateway : ViewGateway where T: TableGateway, new() { // Methods static TableGateway(); protected TableGateway(); public int AddNew(); public static int AddNew(IList entities); public static int AddNew(T entity); public int AddNew(bool returnIdentity); public static int AddNew(T entity, bool returnIdentity); public static int AddNew(IList entities, out Transaction transaction); public static int AddNew(IList entities, bool returnIdentity); public static int AddNew(T entity, out Transaction transaction); public static int AddNew(IList entities, bool returnIdentity, out Transaction transaction); public static int AddNew(T entity, bool returnIdentity, out Transaction transaction); public IDbTransaction BeginTransaction(); public IDbTransaction BeginTransaction(IsolationLevel isolationLevel); public IDbTransaction BeginTransaction(double activeTime); public IDbTransaction BeginTransaction(IsolationLevel isolationLevel, double activeTime); public bool Commit(); protected static int Delete(string condition); protected static int Delete(string condition, out Transaction transaction); public int DeleteById(); public static int DeleteById(T entity); public static int DeleteById(IList entities); public static int DeleteById(IList entities, out Transaction transaction); public static int DeleteById(T entity, out Transaction transaction); public int DeleteByPK(); public static int DeleteByPK(T entity); public static int DeleteByPK(IList entities); public static int DeleteByPK(IList entities, out Transaction transaction); public static int DeleteByPK(T entity, out Transaction transaction); protected void OnPropertyChanged(MethodBase propertyMethod); protected void OnPropertyChanged(string propertyName); protected internal override void RetrieveBySql(string sql); public bool Rollback(); protected static int Update(T entity, string condition); protected static int Update(T entity, string condition, out Transaction transaction); public int UpdateById(); public static int UpdateById(IList entities); public static int UpdateById(T entity); public static int UpdateById(T entity, out Transaction transaction); public static int UpdateById(IList entities, out Transaction transaction); public int UpdateByPK(); public static int UpdateByPK(IList entities); public static int UpdateByPK(T entity); public static int UpdateByPK(IList entities, out Transaction transaction); public static int UpdateByPK(T entity, out Transaction transaction); // Properties public bool Changed { get; } public List ChangedPropertyNames { get; } } public class StoredProcedure : IStoredProcedure { public bool BeginTransaction(); public void CloseReader(IDataReader reader); public bool Commit(); public DataSet ExecuteDataSet(); public DataTable ExecuteDataTable(); public DataTable ExecuteDataTable(); public List ExecuteEntity(); public int ExecuteNonQuery(); public IDataReader ExecuteReader(); public object ExecuteScalar(); protected static void InitializeGateway(GatewayConfig config); protected static void InitializeGateway(DatabaseType dbType, string connectionString); protected void InitializeInstance(T entity); public bool Rollback(); } public class AggregateEntity where T: AggregateEntity, new() { public static List Execute(); protected static List Execute(string condition); public static DataTable ExecuteDataTable(); protected static DataTable ExecuteDataTable(string condition); protected static void InitializeGateway(GatewayConfig config); protected static void InitializeGateway(DatabaseType dbType, string connectionString); // Properties protected static Order SortedOrder { get; set; } } public static class EntityMapper { // Methods public static void AdaptToDatabase(DataTable adaptedTable); public static void AdaptToEntity(DataTable rawTable); public static void CopyToEntities(IList entities, IList adaptedRows); public static void CopyToEntities(IList entities, DataTable adaptedTable); public static void CopyToEntity(T entity, DataRow row); public static List CreateEntities(int count); public static DataTable CreateTable(); public static DataTable CreateTable(bool isAdapted); public static string ToColumnName(string propertyName); public static List ToEntities(IList adaptedRows); public static List ToEntities(DataTable table); public static T ToEntity(DataRow adaptedRow); public static string ToPropertyName(string columnName); public static DataTable ToTable(IList entities); public static DataTable ToTable(params T[] entities); public static DataTable ToTable(bool isAdapted, params T[] entities); public static DataTable ToTable(bool isAdapted, IList entities); } public static class EntityUtility { // Methods public static List Inherit(IList entities); public static T Inherit(object entity); public static T Inherit(Tbase baseEntity, TransformAction method); public static List Inherit(IList baseEntities, TransformAction method); public static void ShadowCopy(IList targetEntities, IList sourceEntities); public static void ShadowCopy(object targetEntity, object sourceEntity); }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值