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

 

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章