Automapper - как сопоставить параметры конструктора вместо установщиков свойств


в случаях, когда мои целевые сеттеры являются частными, я могу захотеть сопоставить объект с помощью конструктора целевого объекта. Как бы вы сделали это с помощью Automapper?

4 87

4 ответа:

использовать ConstructUsing

это позволит вам указать, какой конструктор использовать в течение сопоставления. но тогда все остальные свойства будут автоматически сопоставлены в соответствии с соглашениями.

Также обратите внимание, что это отличается от ConvertUsing в этом преобразовании использование не будет продолжать отображаться через соглашения, вместо этого он даст вам полный контроль над отображением.

Mapper.CreateMap<ObjectFrom, ObjectTo>()
    .ConstructUsing(x => new ObjectTo(arg0, arg1, etc));

...

using AutoMapper;
using NUnit.Framework;

namespace UnitTests
{
    [TestFixture]
    public class Tester
    {
        [Test]
        public void Test_ConstructUsing()
        {
            Mapper.CreateMap<ObjectFrom, ObjectTo>()
                .ConstructUsing(x => new ObjectTo(x.Name));

            var from = new ObjectFrom { Name = "Jon", Age = 25 };

            ObjectTo to = Mapper.Map<ObjectFrom, ObjectTo>(from);

            Assert.That(to.Name, Is.EqualTo(from.Name));
            Assert.That(to.Age, Is.EqualTo(from.Age));
        }
    }

    public class ObjectFrom
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class ObjectTo
    {
        private readonly string _name;

        public ObjectTo(string name)
        {
            _name = name;
        }

        public string Name
        {
            get { return _name; }
        }

        public int Age { get; set; }
    }
}

вы должны использовать Map метод, который позволяет установить назначение. Например :

Mapper.CreateMap<ObjectFrom, ObjectTo>()

var from = new ObjectFrom { Name = "Jon", Age = 25 };

var to = Mapper.Map(from, new ObjectTo(param1));

рекомендуется использовать документированные подходы из AutoMapper https://github.com/AutoMapper/AutoMapper/wiki/Construction

public class SourceDto
{
        public SourceDto(int valueParamSomeOtherName)
        {
            Value = valueParamSomeOtherName;
        }

        public int Value { get; }
}

Mapper.Initialize(cfg => cfg.CreateMap<Source, SourceDto>().ForCtorParam("valueParamSomeOtherName", opt => opt.MapFrom(src => src.Value)));

на момент написания этого ответа AutoMapper сделает это автоматически (с помощью простого CreateMap<>() вызов) для вас, если свойства соответствуют параметрам конструктора. Конечно, если вещи не совпадают, то с помощью .ConstructUsing(...) - это путь.

public class PersonViewModel
{
    public int Id { get; set; }

    public string Name { get; set; }
}

public class Person
{
    public Person (int id, string name)
    {
        Id = id;
        Name = name;
    }

    public int Id { get; }

    public string Name { get; }
}

public class PersonProfile : Profile
{
    public PersonProfile()
    {
        CreateMap<PersonProfile, Person>();
    }
}

Примечание: это предполагает, что вы используете профили для настройки сопоставлений automapper.

при использовании, как показано ниже, это дает правильный объект:

var model = new PersonModel
{
    Id = 1
    Name = "John Smith"
}

// will correctly call the (id, name) constructor of Person
_mapper.Map<Person>(model);

вы можете прочитать больше о конструкция automapper в официальном wiki на GitHub