【Stack Overflow -- 原創加工、原創整理、生產實戰】-- 深度複製

来源:http://www.cnblogs.com/Meng-NET/archive/2017/07/11/7152159.html
-Advertisement-
Play Games

一、說明 1.本程式的核心代碼不是我原創的,是我在Stack Overflow上搜集後加工出來的,原作者已忘記了~ 2.這段程式是我在上海攜程(2014年左右)上班時整理併在生產環境應用的,先後經歷了三家公司項目中使用,穩定可靠,放心使用 3.擴展方法部分可根據自己實際需要修改,流可以搞個stati ...


一、說明

  1.本程式的核心代碼不是我原創的,是我在Stack Overflow上搜集後加工出來的,原作者已忘記了~

  2.這段程式是我在上海攜程(2014年左右)上班時整理併在生產環境應用的,先後經歷了三家公司項目中使用,穩定可靠,放心使用

  3.擴展方法部分可根據自己實際需要修改,流可以搞個static,pool,也可以每次 new,根據項目性能需求自己定製就行了

二、代碼

  代碼如下:

  核心類  NonSerialiazableTypeSurrogateSelector :  

  1     /// <summary>
  2     /// 深度複製 / Surrogate
  3     /// </summary>
  4     public class NonSerialiazableTypeSurrogateSelector : ISerializationSurrogate, ISurrogateSelector
  5     {
  6         /// <summary>
  7         /// _nextSelector
  8         /// </summary>
  9         ISurrogateSelector _nextSelector;
 10 
 11         #region ISerializationSurrogate / 實現
 12         /// <summary>
 13         /// GetObjectData
 14         /// </summary>
 15         public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
 16         {
 17             FieldInfo[] fieldInfos = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
 18             foreach (var fi in fieldInfos)
 19             {
 20                 if (IsKnownType(fi.FieldType))
 21                 {
 22                     info.AddValue(fi.Name, fi.GetValue(obj));
 23                 }
 24                 else if (fi.FieldType.IsClass)
 25                 {
 26                     info.AddValue(fi.Name, fi.GetValue(obj));
 27                 }
 28             }
 29         }
 30 
 31         /// <summary>
 32         /// SetObjectData
 33         /// </summary>
 34         public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
 35         {
 36             FieldInfo[] fieldInfos = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
 37             foreach (var fi in fieldInfos)
 38             {
 39                 if (IsKnownType(fi.FieldType))
 40                 {
 41                     if (IsNullableType(fi.FieldType))
 42                     {
 43                         Type argumentValueForTheNullableType = GetFirstArgumentOfGenericType(fi.FieldType);
 44                         fi.SetValue(obj, info.GetValue(fi.Name, argumentValueForTheNullableType));
 45                     }
 46                     else
 47                     {
 48                         fi.SetValue(obj, info.GetValue(fi.Name, fi.FieldType));
 49                     }
 50                 }
 51                 else if (fi.FieldType.IsClass)
 52                 {
 53                     fi.SetValue(obj, info.GetValue(fi.Name, fi.FieldType));
 54                 }
 55             }
 56             return obj;
 57         }
 58         #endregion
 59 
 60         #region ISurrogateSelector / 實現
 61         /// <summary>
 62         /// ChainSelector
 63         /// </summary>
 64         public void ChainSelector(ISurrogateSelector selector)
 65         {
 66             this._nextSelector = selector;
 67         }
 68 
 69         /// <summary>
 70         /// GetNextSelector
 71         /// </summary>
 72         public ISurrogateSelector GetNextSelector()
 73         {
 74             return _nextSelector;
 75         }
 76 
 77         /// <summary>
 78         /// GetSurrogate
 79         /// </summary>
 80         public ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
 81         {
 82             if (IsKnownType(type))
 83             {
 84                 selector = null;
 85                 return null;
 86             }
 87             else if (type.IsClass || type.IsValueType)
 88             {
 89                 selector = this;
 90                 return this;
 91             }
 92             else
 93             {
 94                 selector = null;
 95                 return null;
 96             }
 97         }
 98         #endregion
 99 
100         #region 私有方法
101         /// <summary>
102         /// 是否為已知類型 / String,Primitive,Serializable
103         /// </summary>
104         private bool IsKnownType(Type type)
105         {
106             return type == typeof(string) || type.IsPrimitive || type.IsSerializable;
107         }
108 
109         /// <summary>
110         /// 是否為可空類型
111         /// </summary>
112         private bool IsNullableType(Type type)
113         {
114             if (type.IsGenericType)
115             {
116                 return type.GetGenericTypeDefinition() == typeof(Nullable<>);
117             }
118             return false;
119         }
120 
121         /// <summary>
122         /// GetFirstArgumentOfGenericType
123         /// </summary>
124         private Type GetFirstArgumentOfGenericType(Type type)
125         {
126             return type.GetGenericArguments()[0];
127         }
128         #endregion
129     }
NonSerialiazableTypeSurrogateSelector.cs

  擴展類 ObjectMethodExtensions :

 1     public static class ObjectMethodExtensions
 2     {
 3         /// <summary>
 4         /// 深度複製 (值類型/包裝類型/引用類型/序列化/非序列化/標識序列化/非標識序列化,皆可深度複製)
 5         /// </summary>
 6         public static T DeepClone<T>(this T obj)
 7         {
 8             var result = default(T);
 9             try
10             {
11                 IFormatter formatter = new BinaryFormatter();
12                 formatter.SurrogateSelector = new SurrogateSelector();
13                 formatter.SurrogateSelector.ChainSelector(new NonSerialiazableTypeSurrogateSelector());
14                 var ms = new MemoryStream();
15                 formatter.Serialize(ms, obj);
16                 ms.Position = 0;
17                 result = (T)formatter.Deserialize(ms);
18             }
19             catch (Exception ex)
20             {
21                 throw new Exception("方法:DeepClone<T>(this T obj)出錯.", ex);
22             }
23             return result;
24         }
25     }
ObjectMethodExtensions.cs  

三、.Net 內置類 與 代碼說明

  BinaryFormatter:

  以二進位格式序列化和反序列化對象或連接對象的整個圖形。

  https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx 

  SurrogateSelector:

  可幫助您選擇要委派序列化或反序列化到的進程的序列化代理項中的格式化程式。

  https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.surrogateselector(v=vs.110).aspx

  MemoryStream :

  創建一個流,其後備存儲為記憶體。

  https://msdn.microsoft.com/zh-cn/library/system.io.memorystream.aspx

  ISerializationSurrogate :

  Implements a serialization surrogate selector that allows one object to perform serialization and deserialization of another.

  (自己翻譯~)

  https://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializationsurrogate(v=vs.110).aspx

  ISurrogateSelector:

  指示序列化代理項選擇器類。

  https://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.isurrogateselector

四、使用方式

  直接在要深度複製的實例對象後.DeepClone()即可,如:

  當然如果你不嫌麻煩,也可以指定類型,如:

  使用,是就是這樣使用就行了,其中 擴展方法部分 可根據使用的頻次做性能優化~

 

 

                                         蒙

                                    2017-07-11 19:07  周二

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • linux系統是多用戶(Multi-users)和多任務(Multi-tasks)的,這樣的目的是為了一臺linux主機可以給很多用戶提供服務同時運行多種服務,但是我們是怎麼區分每個用戶呢?作為一個管理員我對linux系統許可權有哪些?作為一個普通的用戶又可以對linux系統有哪些操作呢?這裡就牽扯到 ...
  • 本文所選的例子來自於《Advanced Bash-scripting Gudie》一書,譯者 楊春敏 黃毅 腳本運行結果 ...
  • 關於圖形界面的配置,我這裡就不多介紹了,這個很簡單。這裡介紹的是如何通過修改配置文件來實現虛擬網卡。 首先介紹ubuntu(我這裡使用的是ubuntu-16.04)下虛擬網卡的配置 1、先用ifconfig查看當前的網卡配置 一般沒有進行設置之前,列印的信息如上所示。 2、查看當前網卡配置,打開配置 ...
  • using System.Collections.Generic;//引用命名空間//Dictionary可以理解為散列集合 public class DictionaryTest { public static void Main() { //1.初始化 Dictionary dicA = new... ...
  • -> List<T> 線性集合,長度可變的數組 -> 增 Add() AddRange() Insert() 添加一個元素list.Add("張三"); 添加一組元素 string[] temArr={"張三","李四","王五"}; list.AddRange(temArr); 插入一個元素 li ...
  • 單例子模式定義 保證一個類僅有一個實例,並提供一個訪問它的全局訪問點. 通常我們可以讓一個全局變數使得一個對象被訪問,但它不能防止你實例化多個對象。一個最好的辦法就是讓類自身負責保存它的唯一實例。這個類可以保證沒有其它實例可以唄創建並且它可以提供一個訪問該實例的方法,這就是單例模式。 單例子模式簡單 ...
  • 數據統計是每個系統中必備的功能,在給領導彙報統計數據,工作中需要的進展數據時非常有用。 在我看來,一個統計的模塊應該實現以下功能: 能夠將常用的查詢的統計結果顯示出來; 顯示的結果可以是表格形式,也可以是圖形形式,如果是圖形的話能夠以多種形式顯示(柱狀圖、折線圖、餅圖、雷達圖、堆疊柱狀圖等): 統計 ...
  • 《.NET 規範》第 3 章 命名規範 3.1 大小寫約定 要把 PascalCasing 用於由多個單詞構成的命名空間、類型以及成員的名字。 要把 camelCasing 用於參數的名字。 要把兩個字母的首字母縮寫詞全部大寫,除非它是 camelCasing 風格的參數名的第一個單詞。 要把由三個 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...