【问题标题】:Copy object to object (with Automapper ?)将对象复制到对象(使用 Automapper ?)
【发布时间】:2011-08-08 11:39:03
【问题描述】:

我有一堂课:

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

我有两个 Person 实例(person1 和 person2)。我想将 person2 的内容复制到 person1。我想在一条指令中制作此副本,并且逐个属性地制作:

person1.LastName = person2.LastName;

在文档中,我看到将一个对象复制到另一个对象,但类型不同。类型相同时如何复制对象?

【问题讨论】:

  • @Darin - 这将创建一个参考,而不是一个副本。
  • @Uw Concept,是的,但由于问题不是很清楚,我想我可能会建议这个。
  • 不想创建一个引用,而是一个完全独立的副本
  • 我建议不要为此使用 AutoMapper - 它不是为克隆项目而设计的(尽管它可能在某些情况下工作)。相反,BinaryFormatter 技巧很神奇,并且很容易封装在扩展方法中。
  • 从概念上讲,不,它们不是同一个操作。克隆还涉及私人数据,而不仅仅是公共数据。克隆基本上只查看私有字段,而映射不会。

标签: c# automapper


【解决方案1】:

据我了解,OP 不想将 person2 克隆到 Person 的新实例中,而是询问如何复制 的内容person2Person已经存在的实例 (person1)。 AutoMapper 的 Mapper.Map 方法的重载可以为您执行此操作:

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 类的成员属于 Brain 类,并且您在复制数据 Mapper.Map&lt;Person, Person&gt;(person2, person1); 调用之前还完成了 Mapper.CreateMap&lt;Brain, Brain&gt;();,则 person1 将保留其当前的 Brain 实例,但此 Brain 将接收 person2Brain 的成员值实例。那就是你有一个深拷贝
但是如果 AutoMapper 在复制之前没有 Brain-Brain 映射,那么 person1Brain 成员将引用相同的 Brain 实例作为person2 引用。那就是你会得到一个浅拷贝
这递归地适用于所有成员,因此您最好确保 AutoMapper 具有您想要深度复制的成员类的映射,并且没有您想要浅拷贝的成员类的映射。

使用 AutoMapper 的替代方法是使用 an approach using reflection。 (请注意,链接中的代码会进行 shallow 复制!)

“支持填充现有对象,而不是 AutoMapper 自己创建目标对象”为 added in AutoMapper version 0.2

【讨论】:

  • 这似乎适用于对象级别,但其他对象作为属性是通过引用复制的。也许有一种方法可以告诉 automapper 克隆属性而不是复制 ref?
【解决方案2】:

既然你问With Automapper?,我可以建议你不要使用AutoMapper吗?

改为在Clone 方法中使用MemberwiseClone(),例如

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

【讨论】:

  • 唯一的问题是你现在声明你的 Person 类型可以被克隆。这在语义上是不正确的,目标是从一个实例复制(不是克隆)到另一个实例。
  • 您能否详细说明与此具体示例的差异?
  • wal:MemberwiseClone 创建一个 Person 的 new 实例。 OP 希望保留 Person1 指向的现有实例,并用 Person2 的值填充它。如果将 Person1 重定向到新实例,则可能有对 Person1 指向的实例的其他引用不会获得所需的数据更新。
  • object.MemberwiseClone() 执行浅拷贝,顺便说一下,不是深拷贝。 google.ch/…
  • 你没有解释为什么不使用 AutoMapper?我是不是认为return (Person) MemberwiseClone(); 是一种不好的做法或仅仅是“代码味道”的人?
【解决方案3】:
Mapper.CreateMap<Person, Person>();

// Perform mapping

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

希望这会有所帮助。

【讨论】:

  • 不应该是Mapper.Map&lt;Person, Person&gt;(person2, person1);吗?您的方式将创建一个新对象 person1 (我在回答中被杀;))
  • 对于在此处使用 google 的人: Map.CreateMap 已删除,此处描述了配置映射的新方法 stackoverflow.com/a/38194308/4547594
  • Automapper 是只复制简单的属性还是复制额外的导航属性?如何告诉它只复制简单属性而不复制对象属性?
  • 我发现如果 Person 是从另一个映射映射的嵌套属性,那么它只会复制相同的实例而不是映射到新实例。
【解决方案4】:

在当前版本的 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()

【讨论】:

  • 但是 OP 不想要对象的克隆或副本,任务是复制到现有对象中
  • @PandaWood 代替var clone = Mapper.Map&lt;Person&gt;(person); 你可以使用Mapper.Map(person, clone);
【解决方案5】:

您为什么要为此使用 Automapper?一个简单的克隆将为您完成这项工作。

在此处阅读更多信息:Deep cloning objects

【讨论】:

  • 因为 AutoMapper 使用反射比二进制序列化更快。
  • 而且 AutoMapper 并不要求所有涉及的类型都被标记为 [Serializable]。 AutoMapper 也是可配置的;如果您只想复制一些字段,或者在复制过程中进行某种转换,它可以做到这一点。 :-)
  • 一个“简单”的深度克隆?我们对简单有不同的定义。
  • @WouterHuysentruit Automapper 还允许您对映射进行单元测试。如果您在以后的生活中修改类型,那就太好了。
  • 因为 AutoMapper 可能出于其他原因在不同的关注级别上使用 - 假设 AutoMapper 有任何有效用途,那么在该用途中,可能希望克隆子属性而不是通过引用复制。
猜你喜欢
  • 1970-01-01
  • 2021-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多