【问题标题】:Mapping from dynamic to type with property defined with interface type使用接口类型定义的属性从动态映射到类型
【发布时间】:2019-01-10 15:53:03
【问题描述】:

上下文是我想将dynamic dapper 结果映射到一个对象,并且该对象具有一个具有接口类型的属性:

public class TargetModel
{
    public int Id { get; set; }
    public IAddress AbstractAddress { get; set; }
}

动态到对象位是直截了当的,但我无法配置 AutoMapper 来告诉它如何处理接口。

dynamic sourceModel = new ExpandoObject();

// flat model - id should map to TargetModel, Address01 will map to a nested type Address on TargetModel
sourceModel.Id = 1;
sourceModel.Address01 = "address01";

// for debugging purposes address maps ok from dynamic
Address address = Mapper.Map<Address>(sourceModel);

// this maps, but AbstractAddress is null - I need to config AutoMapper to understand how to map IAddress to Address
TargetModel target = Mapper.Map<TargetModel>(sourceModel);

我试图告诉它如何处理该属性:

CreateMap<ExpandoObject, TargetModel>()
    .ForMember(y => y.AbstractAddress, opts => opts.MapFrom(f => f));

失败的原因是:

System.ArgumentException: 无法创建接口类型的实例

所以我试图暗示具体:

CreateMap<IAddress, Address>().As<Address>();

这不能解决问题并且异常仍然存在。

我查看了以下问题/概念并尝试了各种配置选项,但无法使地图正常工作:

【问题讨论】:

  • “不知道如何处理”和“goes pear”是模棱两可的问题描述。你能告诉我们具体的问题吗?例如。编译或运行时错误、数据未复制、数据复制不正确等
  • @JohnWu 更新为更具体。
  • @LucianBargaoanu 我可以看到它在没有配置/提示的情况下映射了动态,但我不知道如何确保映射带有接口的属性。
  • 您需要创建一个从字符串到 IAddress 的映射。默认情况下,AM 将创建一个代理,但如果您需要 Address,则必须使用 As 告诉 AM。

标签: c# .net dynamic automapper


【解决方案1】:

这是试图从ExpandoObject 中的string 映射到目标类型中的IAddress。显然它不能创建一个 IAddress 的实例来填充,所以你必须自己在映射中实现它。

如果您的模型如下所示:

public class TargetModel
{
    public int Id { get; set; }
    public IAddress AbstractAddress { get; set; }
}

public interface IAddress
{
    string Address01 { get; set; }
}

public class Address : IAddress
{
    public string Address01 { get; set; }
}

那么您的配置和设置可能如下所示:

public void MappingTests()
{
    dynamic sourceModel = new ExpandoObject();

    // flat model - id should map to TargetModel, Address01 will map to a nested type Address on TargetModel
    sourceModel.Id = 1;
    sourceModel.Address01 = "address01";

    Mapper.Initialize(cfg =>
    {
        cfg.CreateMap<ExpandoObject, TargetModel>()
        .ForMember(dest => dest.AbstractAddress, opt => opt.MapFrom(src => new Address() { Address01 = src.First(kvp => kvp.Key == "Address01").Value.ToString() }))
        .ForMember(destinationMember => destinationMember.Id, opt => opt.MapFrom(src => src.First(kvp => kvp.Key == "Id").Value));
    });

    TargetModel target = Mapper.Map<TargetModel>(sourceModel);
}

我只是将它用作IEnumerable&lt;KeyValuePair&lt;string, object&gt;&gt;,但您也可以通过强制转换将 expando 对象视为字典。

cfg.CreateMap<ExpandoObject, TargetModel>()
    .ForMember(dest => dest.AbstractAddress, opt => opt.MapFrom(src => new Address() { Address01 = ((IDictionary<string, object>)src)["Address01"].ToString() }))
    .ForMember(destinationMember => destinationMember.Id, opt => opt.MapFrom(src => ((IDictionary<string, object>)src)["Id"]));

【讨论】:

  • 它非常明确,并且与简单地新建对象并手动设置属性相距不远 - AutoMapper 是否没有内置方法来映射这些而不通过配置显式设置属性?跨度>
  • 我同意,这不好。但这是我知道的唯一方法。也许那里有更好的东西,希望
猜你喜欢
  • 1970-01-01
  • 2021-08-15
  • 1970-01-01
  • 2015-06-03
  • 2014-05-21
  • 2018-02-19
  • 1970-01-01
  • 2012-06-16
  • 1970-01-01
相关资源
最近更新 更多