2017-04-04 173 views
2

如何让AutoMapper将缺少的未映射属性映射到目标对象内的字典? (像序列化过程中ExtensionDataAutoMapper将未映射的属性映射到Dictionary/ExtensionData

例子:

class Source 
{ 
    public int A {get;set;} 
    public int B {get;set;} 
    public int C {get;set;} 
} 

class Destination 
{ 
    public int A {get;set;} 
    public Dictionary<string, object> D {get;set;} 
} 

Source s = new Source { A = 1, B = 2, C = 3 }; 
Destination d = ... // Mapping code 

现在我想以下结果:

d.A ==> 1 
d.D ==> {{ "B", 2 }, { "C", 3 }} 

*编辑*

最后,我要寻找一个解决方案没有反射。含义:在设置/配置/初始化过程中允许反射,但在映射本身期间,我不希望由反射引起任何延迟。

*编辑*

我要寻找一个通用的解决方案,就像序列化。

+0

我不相信有一个内置的功能,要做到这一点,但是你可以创建一个使用反射来比较源自定义解析和目标物业并从那里去。 –

+0

我已经与自定义解析器搏斗......但这是一个痛苦。我无法想象我是第一个进入这个领域的人,因为序列化程序具有此功能(它也将数据从一个“对象”映射到另一个)。 –

回答

4

对于您的问题有很多可能的解决方案。 我已经为你的财产创建自定义的值解析器和它完美的作品:

public class CustomResolver : IValueResolver<Source, Destination, Dictionary<string, object>> 
{ 
    public Dictionary<string, object> Resolve(Source source, Destination destination, Dictionary<string, object> destMember, ResolutionContext context) 
    { 
     destMember = new Dictionary<string, object>(); 

     var flags = BindingFlags.Public | BindingFlags.Instance; 
     var sourceProperties = typeof(Source).GetProperties(flags); 

     foreach (var property in sourceProperties) 
     { 
      if (typeof(Destination).GetProperty(property.Name, flags) == null) 
      { 
       destMember.Add(property.Name, property.GetValue(source)); 
      } 
     } 

     return destMember; 
    } 
} 

如何使用它?

static void Main(string[] args) 
{ 
    Mapper.Initialize(cfg => { 
     cfg.CreateMap<Source, Destination>() 
      .ForMember(dest => dest.D, opt => opt.ResolveUsing<CustomResolver>()); 
    }); 

    var source = new Source { A = 1, B = 2, C = 3 }; 

    var result = Mapper.Map<Source, Destination>(source); 
} 

public class Source 
{ 
    public int A { get; set; } 
    public int B { get; set; } 
    public int C { get; set; } 
} 

public class Destination 
{ 
    public int A { get; set; } 
    public Dictionary<string, object> D { get; set; } 
} 
+0

不错的解决方案。我选择AutoMapper来防止使用反射读取/写入数据,因为它很慢。 AutoMapper优化了这个过程。我希望有一个解决方案,最终,我有一个完全优化的映射过程,不会有明显的延迟。 Anwyay ... +1给你。 –

+0

我编辑了我的问题,所以你的回答不再符合标准。但是,对我来说,这是一个非常好的开始。 –

+0

AutoMapper正在使用Reflection。 https://msdn.microsoft.com/en-us/library/system.reflection.emit(v=vs.110).aspx 我不确定是否有可能检测未映射的属性没有反射。 –

2

我喜欢Pawel的解决方案,因为它更通用。 如果你想要的东西简单,但不通用的,你可以初始化这样的映射:

Mapper.Initialize(cfg => { 
          cfg.CreateMap<Source, Destination>() 
           .ForMember(dest => dest.D, 
             opt => opt.MapFrom(r => new Dictionary<string,object>(){{ "B", r.B},{ "C", r.C}})); 
    }); 
+0

Thanx。是的,我正在寻找一个通用的解决方案。仍+1。 –