AutoMapper 将 Class 配置为动态
AutoMapper configure Class to dynamic
我们使用AutoMapper导入动态配置的CSV文件来设置映射。我们使用 ExpandoObjects 作为源,这工作正常。
我想对灵活的导出功能使用类似的方法。但是,我找不到配置从 class 类型到动态类型的动态映射的方法。我查看了源代码 here 但如何在运行时为动态类型提供有效的 MapExpression?
这似乎是一个可行的解决方案 - 将动态对象替换为在运行时创建的 class。基于 this post:
创建 class 类型
using AutoMapper;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace AutoMapperDynamicDest
{
public class Bar
{
public string Bar1 { get; set; }
public string Bar2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
// create a new class type - property definition should come from a configuration file
var myDynamicType = CreateMyType(new (string PropName, Type PropType)[] { ("Foo1", typeof(string)), ("Foo2", typeof(string)) });
var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Bar), myDynamicType)
.ForAllMembers(o =>
{
// again, this should come from a configuration file
switch(o.DestinationMember.Name)
{
case "Foo1":
//o.MapFrom(s => ((Bar)s).Bar1);
o.MapFrom("Bar1");
break;
default:
o.Ignore();
break;
}
}));
// Remove in production - test only
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
// This is the data object to be exported
var bar = new Bar();
bar.Bar1 = "This should be mapped to Foo1";
// Map the data object to a new object of dynamic type
dynamic res = mapper.Map(bar, typeof(Bar), myDynamicType);
if (res.Foo1 != "This should be mapped to Foo1")
{
Console.WriteLine("Map did not succeed");
}
else
{
Console.WriteLine("Mapped successfully from Bar.Bar1 to dynamic.Foo1");
}
Console.ReadKey();
}
/// <summary>
/// Creates a class type with properties on the fly
/// </summary>
public static Type CreateMyType(IEnumerable<(string PropName, Type PropType)> properties)
{
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
TypeBuilder typeBuilder = moduleBuilder.DefineType(
"MyNamespace.TypeName", TypeAttributes.Public | TypeAttributes.Class);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
foreach (var prop in properties)
{
CreateProperty(typeBuilder, prop.PropName, prop.PropType);
}
// Create the type itself
Type newType = typeBuilder.CreateType();
return newType;
}
public static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label 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);
}
}
}
我们使用AutoMapper导入动态配置的CSV文件来设置映射。我们使用 ExpandoObjects 作为源,这工作正常。
我想对灵活的导出功能使用类似的方法。但是,我找不到配置从 class 类型到动态类型的动态映射的方法。我查看了源代码 here 但如何在运行时为动态类型提供有效的 MapExpression?
这似乎是一个可行的解决方案 - 将动态对象替换为在运行时创建的 class。基于 this post:
创建 class 类型using AutoMapper;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace AutoMapperDynamicDest
{
public class Bar
{
public string Bar1 { get; set; }
public string Bar2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
// create a new class type - property definition should come from a configuration file
var myDynamicType = CreateMyType(new (string PropName, Type PropType)[] { ("Foo1", typeof(string)), ("Foo2", typeof(string)) });
var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Bar), myDynamicType)
.ForAllMembers(o =>
{
// again, this should come from a configuration file
switch(o.DestinationMember.Name)
{
case "Foo1":
//o.MapFrom(s => ((Bar)s).Bar1);
o.MapFrom("Bar1");
break;
default:
o.Ignore();
break;
}
}));
// Remove in production - test only
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
// This is the data object to be exported
var bar = new Bar();
bar.Bar1 = "This should be mapped to Foo1";
// Map the data object to a new object of dynamic type
dynamic res = mapper.Map(bar, typeof(Bar), myDynamicType);
if (res.Foo1 != "This should be mapped to Foo1")
{
Console.WriteLine("Map did not succeed");
}
else
{
Console.WriteLine("Mapped successfully from Bar.Bar1 to dynamic.Foo1");
}
Console.ReadKey();
}
/// <summary>
/// Creates a class type with properties on the fly
/// </summary>
public static Type CreateMyType(IEnumerable<(string PropName, Type PropType)> properties)
{
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
TypeBuilder typeBuilder = moduleBuilder.DefineType(
"MyNamespace.TypeName", TypeAttributes.Public | TypeAttributes.Class);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
foreach (var prop in properties)
{
CreateProperty(typeBuilder, prop.PropName, prop.PropType);
}
// Create the type itself
Type newType = typeBuilder.CreateType();
return newType;
}
public static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label 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);
}
}
}