using System.Reflection; using System.Reflection.Emit; using Hotline.Share.Dtos; using Hotline.Share.Dtos.Order; using MiniExcelLibs.Attributes; using XF.Domain.Extensions; namespace Hotline.Tools; public class DynamicClassHelper { public static Type CreateDynamicClass(List propInfos) { string className = "DynamicClass"; AssemblyName assemblyName = new AssemblyName("DynamicAssembly"); AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public); foreach (var property in propInfos.OrderBy(d => d.Sort).ToList()) { var propertyName = property.Prop.Trim().ToPascalCase(); var propertyType = typeof(string); FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private); PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null); MethodAttributes getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + propertyName, getSetAttributes, propertyType, Type.EmptyTypes); ILGenerator getIL = getMethodBuilder.GetILGenerator(); getIL.Emit(OpCodes.Ldarg_0); getIL.Emit(OpCodes.Ldfld, fieldBuilder); getIL.Emit(OpCodes.Ret); MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_" + propertyName, getSetAttributes, null, new Type[] { propertyType }); ILGenerator setIL = setMethodBuilder.GetILGenerator(); setIL.Emit(OpCodes.Ldarg_0); setIL.Emit(OpCodes.Ldarg_1); setIL.Emit(OpCodes.Stfld, fieldBuilder); setIL.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getMethodBuilder); propertyBuilder.SetSetMethod(setMethodBuilder); var columnNameCtorInfo = typeof(ExcelColumnNameAttribute).GetConstructor(new Type[] { typeof(string), typeof(string[]) }); var attributeBuilder = new CustomAttributeBuilder(columnNameCtorInfo, new object[] { property.Name, null }); propertyBuilder.SetCustomAttribute(attributeBuilder); } Type generatedType = typeBuilder.CreateType(); return generatedType; } public static Type CreateDynamicClass(List propInfos) { string className = "DynamicClass"; AssemblyName assemblyName = new AssemblyName("DynamicAssembly"); AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public); var sourceProps = typeof(TSource).GetProperties(); InitTypeBuilder(propInfos, sourceProps, typeBuilder); Type generatedType = typeBuilder.CreateType(); return generatedType; } public static Type CreateDynamicClass(List propInfos, Type tSource) { string className = "DynamicClass"; AssemblyName assemblyName = new AssemblyName("DynamicAssembly"); AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public); var sourceProps = tSource.GetProperties(); InitTypeBuilder(propInfos, sourceProps, typeBuilder); Type generatedType = typeBuilder.CreateType(); return generatedType; } private static void InitTypeBuilder(List propInfos, PropertyInfo[] sourceProps, TypeBuilder typeBuilder) { foreach (var property in propInfos.OrderBy(d => d.Sort).ToList()) { var propertyName = property.Prop.Trim().ToPascalCase(); //var propertyType = sourceProps.FirstOrDefault(d => d.Name == propertyName)?.PropertyType ?? typeof(string); var propertyType = GetPropertyType(property.Prop, sourceProps); FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private); PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null); MethodAttributes getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + propertyName, getSetAttributes, propertyType, Type.EmptyTypes); ILGenerator getIL = getMethodBuilder.GetILGenerator(); getIL.Emit(OpCodes.Ldarg_0); getIL.Emit(OpCodes.Ldfld, fieldBuilder); getIL.Emit(OpCodes.Ret); MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_" + propertyName, getSetAttributes, null, new Type[] { propertyType }); ILGenerator setIL = setMethodBuilder.GetILGenerator(); setIL.Emit(OpCodes.Ldarg_0); setIL.Emit(OpCodes.Ldarg_1); setIL.Emit(OpCodes.Stfld, fieldBuilder); setIL.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getMethodBuilder); propertyBuilder.SetSetMethod(setMethodBuilder); var columnNameCtorInfo = typeof(ExcelColumnNameAttribute).GetConstructor(new Type[] { typeof(string), typeof(string[]) }); var attributeBuilder = new CustomAttributeBuilder(columnNameCtorInfo, new object[] { property.Name, null }); propertyBuilder.SetCustomAttribute(attributeBuilder); if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?)) { var columnExcelFormatCtorInfo = typeof(ExcelFormatAttribute).GetConstructor(new Type[] { typeof(string) }); var excelFormatAttributeBuilder = new CustomAttributeBuilder(columnExcelFormatCtorInfo, new object[] { "yyyy-MM-dd HH:mm:ss" }); propertyBuilder.SetCustomAttribute(excelFormatAttributeBuilder); } } } private static Type GetPropertyType(string propName, PropertyInfo[] sourceProps) { var propNameArray = propName.Split('.', StringSplitOptions.TrimEntries) .Select(d => d.ToPascalCase()) .ToList(); if (propNameArray.Count == 1) { return sourceProps.FirstOrDefault(d => d.Name == propNameArray[0])?.PropertyType ?? typeof(string); } else { var prop = sourceProps.FirstOrDefault(d => d.Name == propNameArray[0]); if (prop == null) return typeof(string); return GetPropertyType(string.Join(".", propNameArray.Skip(1)), prop.PropertyType.GetProperties()); } } }