Sao chép đối tượng sang đối tượng (với Automapper?)


77

Tôi có một lớp học:

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

Tôi có hai trường hợp của Person (person1 và person2). Tôi muốn sao chép nội dung của person2 sang person1. Tôi muốn tạo bản sao này trong một hướng dẫn và không phải thuộc tính của tài sản:

person1.LastName = person2.LastName;

Trong tài liệu, tôi thấy sao chép một đối tượng sang một đối tượng khác nhưng kiểu khác nhau. Làm cách nào tôi có thể sao chép đối tượng khi cùng kiểu?


17
@Darin - Điều đó sẽ tạo ra một tham chiếu, không phải một bản sao.
Steven Ryssaert

1
@Uw Concept, vâng, nhưng vì câu hỏi không rõ ràng lắm, tôi nghĩ tôi có thể đề xuất điều này.
Darin Dimitrov

3
Không muốn tạo một tài liệu tham khảo nhưng một bản sao hoàn toàn độc lập
Kris-I

6
Tôi khuyên bạn không nên sử dụng AutoMapper cho việc này - nó không được thiết kế để sao chép các mục (mặc dù nó có thể hoạt động trong một số trường hợp). Thay vào đó, thủ thuật BinaryFormatter đó hoạt động kỳ diệu và dễ dàng được gói gọn trong một phương thức mở rộng.
Jimmy Bogard

3
Về mặt khái niệm, không, chúng không phải là các hoạt động giống nhau. Nhân bản cũng liên quan đến dữ liệu riêng tư, không chỉ công khai. Nhân bản về cơ bản CHỈ xem xét các trường riêng tư, trong khi ánh xạ thì không.
Jimmy Bogard

Câu trả lời:


85

Như tôi hiểu câu hỏi, OP không muốn sao chép person2 thành một cá thể mới của Person , nhưng đang hỏi cách sao chép nội dung của person2 vào một cá thể đã tồn tại ( person1 ) của Person . Có quá nhiều phương thức Mapper.Map của AutoMapper thực hiện điều này cho bạn:

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

Lưu ý 1: Câu trả lời của @ alexl tạo ra một thể hiện mới của Person . Nếu bạn có các tham chiếu khác đến cá thể mà person1 trỏ tới, những tham chiếu này sẽ không nhận được (có lẽ) cập nhật dữ liệu mong muốn nếu bạn chuyển hướng biến person1 đến một cá thể mới.

Lưu ý 2: Bạn cần lưu ý rằng độ sâu sao chép (đệ quy) phụ thuộc vào những gì mà AutoMapper biết về ánh xạ tại thời điểm ánh xạ!
Nếu một thành viên của Person lớp là nói lớp não và bạn bổ sung đã làm Mapper.CreateMap<Brain, Brain>();trước khi các bản sao dữ liệu Mapper.Map<Person, Person>(person2, person1);cuộc gọi, sau đó PERSON1 sẽ tiếp tục như hiện nay Brain dụ nhưng điều này Brain sẽ nhận được các giá trị thành viên của nhân viên2 's Brain dụ. Đó là bạn có một bản sao sâu .
Nhưng nếu AutoMapper không có ánh xạ Brain-Brain trước khi sao chép, thì của person1 Brainthành viên sẽ tham chiếu cùng một cá thể Brain với tham chiếu một người2 . Đó là bạn sẽ nhận được một bản sao nông .
Điều này áp dụng đệ quy cho tất cả các thành viên, vì vậy tốt hơn bạn nên đảm bảo rằng AutoMapper có ánh xạ cho các lớp thành viên mà bạn muốn sao chép sâu và không có ánh xạ cho các lớp thành viên mà bạn muốn sao chép nông.

Một giải pháp thay thế cho việc sử dụng AutoMapper sẽ là sử dụng một phương pháp sử dụng phản chiếu . (Lưu ý rằng mã trong liên kết là một bản sao cạn !)

"Hỗ trợ điền vào một đối tượng hiện có, thay vì AutoMapper tự tạo đối tượng đích" đã được thêm vào trong phiên bản AutoMapper 0.2 .


điều này dường như hoạt động ở cấp độ đối tượng, nhưng các đối tượng khác dưới dạng thuộc tính được sao chép bằng tham chiếu. Có lẽ có một cách để nói với automapper sao chép các thuộc tính thay vì sao chép một ref?
Sonic Soul

30

Vì bạn đã hỏi, With Automapper?tôi có thể đề nghị bạn không sử dụng AutoMapper không?

Thay vào đó, hãy sử dụng MemberwiseClone()trong một Clonephương pháp, ví dụ:

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

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

CẬP NHẬT

Điều quan trọng cần lưu ý là điều này không ảnh hưởng đến các áp phích gốc muốn sao chép person1 vào person2

Tuy nhiên, (và như @Jimmy Bogard đã chỉ ra) sử dụng MemberwiseClone()được ưu tiên hơn nếu bạn chỉ cần tạo một bản sao (nhân bản) của đối tượng.

Ví dụ: nếu bạn đang làm điều này:

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

sau đó thực sự bạn nên / có thể sử dụng

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

4
Vấn đề duy nhất với điều này là bây giờ bạn đang nói rằng loại Người của bạn có thể được sao chép. Điều này không chính xác về mặt ngữ nghĩa, mục đích là thực hiện một bản sao (không phải là một bản sao) từ một thể hiện này sang thể hiện khác.
Shaun Wilson

bạn có thể vui lòng giải thích về sự khác biệt liên quan đến ví dụ cụ thể này không?
walker

6
wal: MemberwiseClone tạo một phiên bản mới của Person. OP muốn giữ cá thể đã tồn tại mà Person1 trỏ tới và điền vào nó các giá trị của Person2. Có thể có các tham chiếu khác đến cá thể mà Person1 trỏ tới sẽ không nhận được bản cập nhật dữ liệu mong muốn nếu bạn chuyển hướng Person1 đến một cá thể mới.
Ulf Åkerstedt

8
object.MemberwiseClone () thực hiện một bản sao nông, KHÔNG phải bản sao sâu. google.ch/…
Errore Fatale

1
Bạn không giải thích tại sao KHÔNG sử dụng AutoMapper? Tôi là người ở đây nghĩ rằng đó return (Person) MemberwiseClone();là một hành vi xấu hay chỉ đơn giản là một "mùi mã"?
Geka P

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

// Perform mapping

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

Hi vọng điêu nay co ich.


17
Điều này không nên Mapper.Map<Person, Person>(person2, person1);? Theo cách của bạn sẽ tạo một đối tượng mới person1(mà tôi đang bị giết trong câu trả lời của mình;))
wal

2
Đối với những người google tại đây: Map.CreateMap đã bị xóa và cách mới để định cấu hình ánh xạ được mô tả tại đây stackoverflow.com/a/38194308/4547594
Igand

Automapper chỉ sao chép các thuộc tính đơn giản hay nó cũng sao chép các thuộc tính điều hướng bổ sung? Làm thế nào tôi có thể nói nó chỉ sao chép các thuộc tính đơn giản chứ không phải thuộc tính đối tượng?
Naomi

2

Tại sao bạn muốn sử dụng Automapper cho việc này? Một bản sao đơn giản sẽ làm công việc cho bạn.

Đọc thêm tại đây: Đối tượng nhân bản sâu


7
Bởi vì AutoMapper sử dụng phản xạ nhanh hơn tuần tự hóa nhị phân.
huysentruitw

4
Và AutoMapper không yêu cầu tất cả các loại liên quan phải được đánh dấu [Có thể hóa nối tiếp]. AutoMapper cũng có thể cấu hình được; nếu bạn chỉ muốn sao chép một số trường hoặc thực hiện một số loại chuyển đổi như một phần của bản sao, nó có thể làm điều đó. :-)
Jonathan Gilbert

8
Một bản sao sâu "đơn giản"? Chúng tôi có các định nghĩa khác nhau về đơn giản.
Gusdor

3
@WouterHuysentruit Automapper cũng cho phép bạn kiểm tra đơn vị ánh xạ. Tuyệt vời nếu bạn sửa đổi loại sau này trong cuộc sống.
Gusdor

2

Trong phiên bản hiện tại của AutoMapper, bạn không thể sử dụng AutoMapper.Mapper.Mapphương thức tĩnh . Thay vào đó, hãy khởi tạo một trình liên kết mới như sau:

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

var mapper = new Mapper(config);

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

Thông thường, bạn muốn đăng ký trình ánh xạ trong Startup.cstệp để tiêm phụ thuộc và đưa nó vào lớp doanh nghiệp của bạn:

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

    var mapper = new Mapper(config);

    services.AddSingleton(mapper);

    // ...
}

Quan trọng: Không tạo hoặc đưa trình ánh xạ vào lớp thực thể của bạn!

Tất nhiên, bạn nên ưu tiên sử dụng MemberwiseClone()trong những trường hợp đơn giản.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.