【问题标题】:AutoMapper mapping unmapped properties to Dictionary / ExtensionDataAutoMapper 将未映射的属性映射到 Dictionary / ExtensionData
【发布时间】:2017-08-29 09:02:42
【问题描述】:

如何使 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 }}

* 编辑 *

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

* 编辑 *

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

【问题讨论】:

  • 我不相信有一个内置函数可以做到这一点,但是您可以创建一个自定义解析器,使用反射来比较源和目标属性并从那里开始。
  • 我已经在与自定义解析器搏斗了……但这很痛苦。我无法想象我是第一个涉足此领域的人,因为序列化程序具有此功能(还将数据从一个“对象”映射到另一个)。

标签: c# .net automapper-5


【解决方案1】:

您的问题有很多可能的解决方案。 我已经为您的属性创建了一个自定义值解析器,它运行良好:

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

【讨论】:

  • 不错的解决方案。我选择 AutoMapper 来防止使用反射读取/写入数据,因为它很慢。 AutoMapper 优化了该过程。我希望最终有一个解决方案,我有一个完全优化的映射过程,没有任何明显的延迟。 Anwyay...为你+1。
  • 我编辑了我的问题,所以你的回答不再符合标准。但再说一遍:对我来说是一个很好的开始。
  • AutoMapper 正在使用反射。 msdn.microsoft.com/en-us/library/…我不确定是否有可能在不反射的情况下检测到未映射的属性。
  • 是的.. 它在构造/配置过程中使用反射。所以它在映射器的创建过程中使用了反射。当映射器在映射期间构建和使用时,不使用反射。
【解决方案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}}));
    });

【讨论】:

  • 谢谢。是的,我正在寻找一个通用的解决方案。仍然 +1。
猜你喜欢
  • 2019-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-04
  • 1970-01-01
  • 2019-06-23
相关资源
最近更新 更多