欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#如何正确的做深拷贝

程序员文章站 2022-12-09 09:28:11
估计很多人在网上看到各种各样的DeepClone实现, 例如: 1. 通过BinaryFormatter进行二进制序列化 这玩意儿序列化出来的东西还带namespace类型, 尺寸非常大, 调试一下就知道极其不靠谱 有些人又开始动歪脑筋了, 说我搞一个JSON序列化, 或者BSON序列化可不可以 2 ......

估计很多人在网上看到各种各样的deepclone实现, 例如:

 

1. 通过binaryformatter进行二进制序列化

 这玩意儿序列化出来的东西还带namespace类型, 尺寸非常大, 调试一下就知道极其不靠谱

 有些人又开始动歪脑筋了, 说我搞一个json序列化, 或者bson序列化可不可以

2. json/bson序列化

 本质问题还是一样的, object => byte[] => object, 中间产生的垃圾对象太多, 尤其是stream那些

 

所以, 我们需要思考deepclone的本质是啥!

 

如果现在有一个类a, 你自己手写一个clone函数, 那么是不是可以做到效率最高? 答案是显然的, 我知道有什么成员, new一个对象分别赋值就行了.

但是如果这个类a成天改, 维护的成本就比较高昂, 万一哪天忘了改, 就会出现一些奇妙的bug.

 

所以, 类a的clone函数, 是一个重复性的工作.

所有重复性的工作, 都可以通过代码生成来搞.

 

那么会有很多代码生成的答案:

3. 写一个dsl编译器

    不要嘲笑这种方式, protobuf在c++的实现里面, 就有一个原型工厂, 做的是类似的事情. c++里面没有反射只能通过这种方式, 只要把这些脏活累活交给编译器就可以了.

    唯一不同的是, 这是编译前代码生成.

4. 通过emit生成代码

    我们都知道.net平台有比较强的动态性, 可以动态的load/unload assembly. 甚至还可以动态的构造assembly和class和function.

    所以, 我们可以对类a生成一个clone函数, 通过反射获取到其成员, 然后动态生成其clone函数, 就相当于手写的代码, 效率可以做到最高.

    然后可以把生成的函数保存起来. jit也能对其进行优化.

    具体实现可以参考: deepcloner

    C#如何正确的做深拷贝

 

 

     去他的github上面瞄一眼就知道是最佳姿势.

5. 通过expressiontree生成代码

    表达式树也可以生成代码, 具体可以 参考一下

  

   

 

开头那些序列化, 一看就不靠谱, 不知道为啥流传了这么多年