首页 > 代码库 > 【Stack Overflow -- 原创加工、原创整理、生产实战】-- 深度复制
【Stack Overflow -- 原创加工、原创整理、生产实战】-- 深度复制
一、说明
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,Serializable103 /// </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 /// GetFirstArgumentOfGenericType123 /// </summary>124 private Type GetFirstArgumentOfGenericType(Type type)125 {126 return type.GetGenericArguments()[0];127 }128 #endregion129 }
扩展类 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 try10 {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 }
三、.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 周二
【Stack Overflow -- 原创加工、原创整理、生产实战】-- 深度复制