Копіювати об'єкт до об'єкта (за допомогою Automapper?)


77

У мене є клас:

public class Person {
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

У мене є два випадки Person (person1 і person2). Я хотів би скопіювати вміст person2 до person1. Я хотів би зробити цю копію в одній інструкції, а не властивість за властивістю:

person1.LastName = person2.LastName;

У документі я бачу копію об’єкта в інший об’єкт, але тип інший. Як я можу скопіювати об’єкт, коли тип однаковий?


17
@ Дарін - Це створило б посилання, а не копію.
Steven Ryssaert

1
@Uw Concept, так, але оскільки питання не дуже зрозуміле, я думав, що можу запропонувати це.
Дарін Димитров

3
Не хочу створювати посилання, а копію, повністю незалежну
Kris-I,

6
Я рекомендую не використовувати для цього AutoMapper - він не призначений для клонування елементів (хоча це може працювати в деяких сценаріях). Натомість цей трюк BinaryFormatter працює магічно і легко вкладається в метод розширення.
Jimmy Bogard

3
Концептуально ні, це не однакові операції. Клонування стосується також приватних, а не лише публічних даних. Клонування в основному дивиться лише на приватні поля, тоді як відображення - ні.
Jimmy Bogard

Відповіді:


85

Наскільки я розумію питання, OP не хоче клонувати person2 у новий екземпляр Person , але запитує, як скопіювати вміст person2 у вже існуючий екземпляр ( person1 ) Person . Існує перевантаження методу Mapper.Map AutoMapper, який робить це за вас:

Mapper.CreateMap<Person, Person>();
Mapper.Map<Person, Person>(person2, person1);
//This copies member content from person2 into the _existing_ person1 instance.

Примітка 1. Відповідь @ alexl створює новий екземпляр Person . Якщо у вас є інші посилання на екземпляр, на який вказує person1 , вони не отримають (імовірно) бажане оновлення даних, якщо ви перенаправите змінну person1 на новий екземпляр.

Примітка 2: Ви повинні пам’ятати, що (рекурсивна) глибина копіювання залежить від того, про що зіставлення AutoMapper знає на момент відображення!
Якщо член Person класу, скажімо , клас мозок , і ви додатково зробили Mapper.CreateMap<Brain, Brain>();до копіювання даних Mapper.Map<Person, Person>(person2, person1);виклику, то person1 збереже поточний мозок екземпляр , але це Brain буде приймати значення членів PERSON2 «и мозку , наприклад. Тобто у вас є глибока копія .
Але якщо у AutoMapper немає копіювання Brain-Brain перед копіюванням, тоді це Brain person1учасник буде посилатися на той самий мозку Це застосовується рекурсивно до всіх членів, тому вам краще переконатися, що AutoMapper має зіставлення для класів-членів, які потрібно глибоко копіювати, і не має відображень для класів-членів, які потрібно неглибоко копіювати.як посилання на одну особу2 . Тобто ви отримаєте неглибоку копію .

Альтернативою використанню AutoMapper було б використання підходу з використанням відображення . (Зверніть увагу, що код у посиланні робить неглибоку копію!)

"Підтримка заповнення існуючого об'єкта, замість того, щоб AutoMapper створював сам об'єкт призначення", було додано до версії 0.2 AutoMapper .


здається, це працює на рівні об'єкта, але інші об'єкти як властивості копіюються за допомогою посилання. можливо, є спосіб сказати automapper клонувати властивості замість копіювання посилання?
Sonic Soul

30

Оскільки ви запитали, чи With Automapper?можу я запропонувати вам не використовувати AutoMapper?

Натомість використовуйте MemberwiseClone()у Cloneметоді, наприклад

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person Clone()
    {
        return (Person) MemberwiseClone();
    }
}

ОНОВЛЕННЯ

Важливо , щоб відзначити це не оригінальні отримання ідеальної плакати бажання скопіювати person1 в person2

Однак (і, як зазначає @Jimmy Bogard), використання MemberwiseClone()є кращим, якщо вам просто потрібно зробити копію (клон) об'єкта.

Наприклад, якщо ви робите це:

//I need a copy of person1 please! I'll make a new person object 
//and automapper everything into it!
var person2 = new Person2();
Mapper.Map<Person, Person>(person1, person2)

тоді справді ви повинні / могли б використовувати

//oh wait, i can just use this!
var person2 = person1.Clone()

4
Єдина проблема в тому, що ви зараз заявляєте, що ваш тип Person можна клонувати. Це семантично неправильно, мета полягає в тому, щоб виконати копію (не клон) з одного екземпляра в інший екземпляр.
Шон Вільсон

Ви можете, будь ласка, детальніше розповісти про відмінності щодо цього конкретного прикладу?
wal

6
wal: MemberwiseClone створює новий екземпляр Person. OP хоче зберегти вже існуючий екземпляр, на який вказує Person1, і заповнити його значеннями Person2. Можуть бути й інші посилання на екземпляр, на який вказує Person1, який не отримає бажаного оновлення даних, якщо ви перенаправите Person1 на новий екземпляр.
Ульф Окерштедт,

8
object.MemberwiseClone () виконує поверхневу копію, а НЕ глибоку копію. google.ch/…
помилка Fatale

1
Ви не пояснили, чому НЕ використовуєте AutoMapper? Це я тут вважаю return (Person) MemberwiseClone();поганою практикою чи просто "запахом коду"?
Гека П

21
Mapper.CreateMap<Person, Person>();

// Perform mapping

var person1 = Mapper.Map<Person, Person>(person2);

Сподіваюся, це допомагає.


17
Це не повинно бути Mapper.Map<Person, Person>(person2, person1);? Ваш шлях створить новий об’єкт person1(за що мене вбивають у моїй відповіді;))
wal

2
Для людей , які Google тут: Map.CreateMap був вилучений і новий спосіб відображення конфігурації описаний тут stackoverflow.com/a/38194308/4547594
Igand

Чи копіює Automapper лише прості властивості, а також копіює додаткові властивості навігації? Як я можу сказати йому копіювати лише прості властивості, а не властивості об’єкта?
Наомі

2

Чому для цього ви хочете використовувати Automapper? Простий клон зробить роботу за вас.

Детальніше читайте тут: Об’єкти глибокого клонування


7
Тому що AutoMapper використовує відображення, яке швидше, ніж двійкова серіалізація.
huysentruitw

4
І AutoMapper не вимагає позначення всіх задіяних типів [Серіалізувати]. AutoMapper також налаштовується; якщо ви хочете скопіювати лише деякі поля або виконати певне перетворення як частину копії, він може це зробити. :-)
Джонатан Гілберт

8
"Простий" глибокий клон? У нас різні визначення простого.
Гусдор,

3
@WouterHuysentruit Automapper також дозволяє вам модульно тестувати відображення. Чудово, якщо ви внесете зміни в тип пізніше в житті.
Гусдор,

2

У поточній версії AutoMapper ви не можете використовувати статичний AutoMapper.Mapper.Mapметод. Натомість ініціалізуйте новий маппер так:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Person, Person>();
});

var mapper = new Mapper(config);

var clone = mapper.Map<Person>(person);

Зазвичай вам потрібно зареєструвати картограф у Startup.csфайлі для введення залежностей та ввести його у свій бізнес-клас:

public void ConfigureServices(IServiceCollection services)
{
    var config = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Person, Person>();
    });

    var mapper = new Mapper(config);

    services.AddSingleton(mapper);

    // ...
}

Важливо: Не створюйте та не вводьте картограф у своєму класі сутності!

Звичайно, вам слід віддати перевагу використанню MemberwiseClone()в простих випадках.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.