估計很多人在網上看到各種各樣的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
去他的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
開頭那些序列化, 一看就不靠譜, 不知道為啥流傳了這麼多年