AutoMapper将未映射的属性映射到Dictionary / ExtensionData

时间:2017-04-04 08:55:49

标签: c# .net automapper-5

如何让AutoMapper将缺失的未映射属性映射到目标对象内的字典? (与序列化期间的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 }}

*编辑*

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

*编辑*

我正在寻找一种通用解决方案,就像序列化器一样。

2 个答案:

答案 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; }
}

答案 1 :(得分:3)

我喜欢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}}));
    });