C#如何正確的做深拷貝


估計很多人在網上看到各種各樣的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

   

 

 

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

5. 通過ExpressionTree生成代碼

    表達式樹也可以生成代碼, 具體可以 參考一下

  https://www.codeproject.com/articles/1111658/fast-deep-copy-by-expression-trees-c-sharp

    https://stackoverflow.com/questions/23229882/deep-clone-with-expression-new-and-expression-trees

 

開頭那些序列化, 一看就不靠譜, 不知道為啥流傳了這么多年


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM