如果通过 C# 实现对象的深复制 ?

咨询区

  • NakedBrunch

我想实现 引用类型对象 之间的深复制,也就是在新的对象上修改不会影响到老的对象,我用了 C# 提供的 Clone 方法。

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = myObj.Clone();

但貌似这样行不通,请问该如何正确实现?

回答区

  • craastad

如果你的引用类型对象是 json 友好的,那你完全可以借助第三方工具将其转为 Json,比如 Json.NET ,参考如下的 Clone 扩展方法。

public static T Clone<T>(this T theObject)
{
    string jsonData = JsonConvert.SerializeObject(theObject);
    return JsonConvert.DeserializeObject<T>(jsonData);
}

然后像下面这样使用。

NewObject = OldObject.Clone();
  • Stacked

如果你要快速实现,建议使用对象映射化工具 AutoMapper, 它是一个高效并且轻量级的将一个对象转为另一个对象,它的底层使用的是 Lambda 表达式树,参考如下代码:

MyType source = new MyType();
Mapper.CreateMap<MyType, MyType>();
MyType target = Mapper.Map<MyType, MyType>(source);

上面的target就是深copy后的对象,如果你觉得这样还繁琐的化,再封装到一个扩展方法中去。

public static T Copy<T>(this T source)
{
    T copy = default(T);
    Mapper.CreateMap<T, T>();
    copy = Mapper.Map<T, T>(source);
    return copy;
}

然后像下面这样使用。

MyType copy = source.Copy();
  • Marcell Toth

通常来说,做深层的copy,方法有如下几种。

  1. 序列化

本质上来说,序列化是非常慢的一种方式,而且还限制重重,比如说:

  1. BinaryFormatter 需要引用类型必须实现 Serializable 特性。

  2. JsonConverter 需要引用类型必须有无参构造函数。

  1. 表达式树

要先加速,可以使用 Expression Tree 或者 Reflection.Emit 来动态生成深复制代码,但这种原始的方式实现起来特别麻烦,我为此专门写了一个映射工具,参见 github:https://github.com/marcelltoth/ObjectCloner

实现起来非常方便,参考如下代码:

var clone = ObjectCloner.DeepClone(original);

我的方法 ~3x 于 Reflection, ~12x 于 Newtonsoft.Json 。

点评区

其实 Dapper 用的就是 Emit 来实现高速映射, AutoMapper 用的是 Expresstion Tree 实现高速映射,大家有兴趣可以了解下。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#中,要实现类的复制,你可以使用以下几种方式: 1. 使用序列化和反序列化:使用BinaryFormatter或JsonSerializer等序列化器,将对象序列化为字节流或JSON字符串,然后再通过反序列化操作将其转换回新的对象。这种方式会创建一个完全独立的对象副本。 ```csharp using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Json; // 使用BinaryFormatter进行复制 public static T DeepCopy<T>(T obj) { using (MemoryStream memoryStream = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(memoryStream, obj); memoryStream.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(memoryStream); } } // 使用JsonSerializer进行复制 public static T DeepCopyJson<T>(T obj) { using (MemoryStream memoryStream = new MemoryStream()) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); serializer.WriteObject(memoryStream, obj); memoryStream.Position = 0; return (T)serializer.ReadObject(memoryStream); } } ``` 2. 实现ICloneable接口:让需要进行复制的类实现ICloneable接口,并在Clone方法中实现属性的逐个复制或使用其他方式创建新的对象。 ```csharp public class MyClass : ICloneable { public int MyProperty { get; set; } public object Clone() { return new MyClass { MyProperty = this.MyProperty }; } } ``` 然后可以使用Clone方法进行复制: ```csharp MyClass original = new MyClass { MyProperty = 42 }; MyClass clone = (MyClass)original.Clone(); ``` 3. 使用第三方库:还可以使用一些第三方库,如AutoMapper、DeepClone等,它们提供了更高级的复制功能,可以自动处理对象之间的关联关系和复杂结构。 以上是实现类的复制的几种常见方式,你可以根据具体情况选择适合的方法。需要注意的是,如果类中包含引用类型的成员变量,你可能需要对这些成员变量也进行复制,以确保实现完全的复制

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值