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

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

Ответ 1

Используйте 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; }
    }
}

Ответ 2

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

Mapper.CreateMap<ObjectFrom, ObjectTo>()

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

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

Ответ 3

Лучшая практика - использовать документированные подходы от AutoMapper. http://docs.automapper.org/en/stable/Construction.html

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

Ответ 4

Во время написания этого ответа 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<PersonViewModel, Person>();
    }
}

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

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

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

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

Вы можете узнать больше о создании autopper в официальной вики на GitHub.