123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- using System;
- using System.Linq;
- using System.Reflection;
- using System.Reflection.Emit;
- using VCommon.Collections;
- using VCommon.Reflection;
- // ReSharper disable StaticMemberInGenericType
- namespace VCommon.VAutoMapper.Internals
- {
- //REF: StackOverflow.com/a/3862241/2430943
- internal static class MiddleClass
- {
- private static readonly string NameSpace = $"{nameof(VCommon)}.{nameof(VCommon.VAutoMapper)}.MiddleClasses.{nameof(MiddleClass)}";
- private static readonly ModuleBuilder ModuleBuilder;
- static MiddleClass()
- {
- var name = new AssemblyName(NameSpace);
- var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
- ModuleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
- }
- public static Type Create(Type entity, Type dto)
- {
- var midPropNames = dto.GetPublicInstanceProperties().Select(p => p.Name).ToArray();
- var entityProps = entity.GetPublicInstanceProperties().ToDictionary(p => p.Name);
- var typeName = $"{NameSpace}.{entity.Assembly.FullName}!{entity.FullName}->{dto.Assembly.FullName}!{dto.FullName}";
- var tb = ModuleBuilder.DefineType(typeName,
- TypeAttributes.Public |
- TypeAttributes.Class |
- TypeAttributes.AutoLayout,
- null);
- tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
- foreach (var propName in midPropNames)
- {
- if (false == entityProps.TryGetValue(propName, out var field))
- throw new VAutoMapperException($"Missing property [{propName}] in [{entity.FullName}] for [{dto.FullName}]");
- var propertyType = field.PropertyType;
- if (false == propertyType.IsPrimitive)
- {
- var primitiveCheck = propertyType.In(typeof(string), typeof(DateTime), typeof(Guid), typeof(decimal), typeof(TimeSpan));
- var genericCheck = propertyType.IsGenericType && propertyType.GetGenericTypeDefinition().In(typeof(Nullable<>));
- if (genericCheck && primitiveCheck)
- {
- //TODO: 复杂类型支持(递归?)
- throw new NotSupportedException($"Only primitive property support. [{field}] in [{field.DeclaringType?.FullName ?? field.DeclaringType?.Name ?? "Unknown class"}]");
- }
- }
- CreateProperty(tb, field.Name, propertyType);
- }
- var middleType = tb.CreateType();
- VAutoMapper.ConfigMapping(entity, middleType);
- VAutoMapper.ConfigMapping(middleType, dto);
- VAutoMapper.FlushMapper();
- return middleType;
- }
- private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
- {
- var fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
- var propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
- var getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
- var getIl = getPropMthdBldr.GetILGenerator();
- getIl.Emit(OpCodes.Ldarg_0);
- getIl.Emit(OpCodes.Ldfld, fieldBuilder);
- getIl.Emit(OpCodes.Ret);
- var setPropMthdBldr =
- tb.DefineMethod("set_" + propertyName,
- MethodAttributes.Public |
- MethodAttributes.SpecialName |
- MethodAttributes.HideBySig,
- null, new[] { propertyType });
- var setIl = setPropMthdBldr.GetILGenerator();
- var modifyProperty = setIl.DefineLabel();
- var exitSet = setIl.DefineLabel();
- setIl.MarkLabel(modifyProperty);
- setIl.Emit(OpCodes.Ldarg_0);
- setIl.Emit(OpCodes.Ldarg_1);
- setIl.Emit(OpCodes.Stfld, fieldBuilder);
- setIl.Emit(OpCodes.Nop);
- setIl.MarkLabel(exitSet);
- setIl.Emit(OpCodes.Ret);
- propertyBuilder.SetGetMethod(getPropMthdBldr);
- propertyBuilder.SetSetMethod(setPropMthdBldr);
- }
- }
- }
|