如何通过使用AutoMapper映射到仅具有构造函数初始化的对象

问题描述 投票:0回答:2

我也将此问题发布到了https://github.com/AutoMapper/AutoMapper/issues/3372

我有类似的模型:

public class Foo
{
    public Foo(Guid id, string name, IEnumerable<string> enumerable, IReadOnlyDictionary<string, string> readOnlyDic, string[] array, Dictionary<string, string> dic)
    {
        Id = id;
        Name = name;
        Enumerable = enumerable;
        ReadOnlyDic = readOnlyDic;
        Array = array;
        Dic = dic;
    }

    public Guid Id { get; }
    public string Name { get; }
    public IEnumerable<string> Enumerable { get; }
    public IReadOnlyDictionary<string, string> ReadOnlyDic { get; }
    public string[] Array { get; }
    public Dictionary<string, string> Dic { get; }
}
public class FooDto
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public IEnumerable<string> Enumerable { get; set; }
    public IReadOnlyDictionary<string, string> ReadOnlyDic { get; set; }
    public string[] Array { get; set; }
    public Dictionary<string, string> Dic { get; set; }
}

如您所见,Foo是一种“不可变”,没有任何成员的直接设置器。现在,我想将FooDto“应用”到现有的Foo,当然它应该创建一个Foo的新实例。

[TestMethod]
public void revise()
{
    var config = new MapperConfiguration(c => c.CreateMap<FooDto, Foo>());
    var mapper = config.CreateMapper();

    var dto = new FooDto
    {
        Id = Guid.NewGuid(),
        Name = "name",
        Enumerable = new string[] { "e" },
        ReadOnlyDic = new Dictionary<string, string> { { "a", "b" } },
        Array = new string[] { "a" },
        Dic = new Dictionary<string, string> { { "1", "2" } }
    };
    var before = new Foo(
        id: Guid.NewGuid(),
        name: "before",
        enumerable: new string[] { },
        readOnlyDic: new Dictionary<string, string>(),
        array: new string[] { },
        dic: new Dictionary<string, string>());

    var foo = mapper.Map(dto, before);

    Assert.AreEqual(dto.Id, foo.Id);
    Assert.AreEqual(dto.Name, foo.Name);
    Assert.AreEqual(dto.Enumerable.Single(), foo.Enumerable.Single());
    Assert.AreEqual(dto.ReadOnlyDic["a"], foo.ReadOnlyDic["a"]);
    Assert.AreEqual(dto.Array[0], foo.Array[0]);
    Assert.AreEqual(dto.Dic["1"], foo.Dic["1"]);
}

dto不适用于新的foo,但DicDictionary<string, string>的类型。很奇怪。

如何配置AutoMapper以将更改应用于“不可变”对象并为其创建新实例?

添加

我也明确地像这样用ForCtorParam进行了测试:

var config = new MapperConfiguration(c =>
{
    c.CreateMap<FooDto, Foo>()
    .ForCtorParam("id", opt => opt.MapFrom(s => s.Id))
    .ForCtorParam("name", opt => opt.MapFrom(s => s.Name))
    .ForCtorParam("enumerable", opt => opt.MapFrom(s => s.Enumerable))
    .ForCtorParam("readOnlyDic", opt => opt.MapFrom(s => s.ReadOnlyDic))
    .ForCtorParam("array", opt => opt.MapFrom(s => s.Array))
    .ForCtorParam("dic", opt => opt.MapFrom(s => s.Dic));
});

但是它也不起作用。即使有效,它也看起来根本不像convention-based映射。

Add2

有趣的是,如果我像这样从destination创建了source,它就可以工作:

var foo = mapper.Map<Foo>(dto);

但是我真正想要的是,基于源应用的先前实例创建目标类型的新实例。就像mergepartial update

c# automapper
2个回答
-1
投票

您可以使用ForCtorParam执行此操作>

方法1


-1
投票

Automapper(以及几乎所有其他映射器)默认情况下依赖公共设置器。由于您没有公开这些内容,因此需要编写一个自定义ConvertUsing()来告诉它如何进行映射。

© www.soinside.com 2019 - 2024. All rights reserved.