【Stack Overflow -- 原创加工、原创整理、生产实战】-- 深度复制
索引:
一、说明
1.本程序的核心代码不是我原创的,是我在Stack Overflow上搜集后加工出来的,原作者已忘记了~
2.这段程序是我在上海携程(2014年左右)上班时整理并在生产环境应用的,先后经历了三家公司项目中使用,稳定可靠,放心使用
3.扩展方法部分可根据自己实际需要修改,流可以搞个static,pool,也可以每次 new,根据项目性能需求自己定制就行了
二、代码
代码如下:
核心类 NonSerialiazableTypeSurrogateSelector :
/// <summary>
/// 深度复制 / Surrogate
/// </summary>
public class NonSerialiazableTypeSurrogateSelector : ISerializationSurrogate, ISurrogateSelector
{
/// <summary>
/// _nextSelector
/// </summary>
ISurrogateSelector _nextSelector; #region ISerializationSurrogate / 实现
/// <summary>
/// GetObjectData
/// </summary>
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
FieldInfo[] fieldInfos = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var fi in fieldInfos)
{
if (IsKnownType(fi.FieldType))
{
info.AddValue(fi.Name, fi.GetValue(obj));
}
else if (fi.FieldType.IsClass)
{
info.AddValue(fi.Name, fi.GetValue(obj));
}
}
} /// <summary>
/// SetObjectData
/// </summary>
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
FieldInfo[] fieldInfos = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var fi in fieldInfos)
{
if (IsKnownType(fi.FieldType))
{
if (IsNullableType(fi.FieldType))
{
Type argumentValueForTheNullableType = GetFirstArgumentOfGenericType(fi.FieldType);
fi.SetValue(obj, info.GetValue(fi.Name, argumentValueForTheNullableType));
}
else
{
fi.SetValue(obj, info.GetValue(fi.Name, fi.FieldType));
}
}
else if (fi.FieldType.IsClass)
{
fi.SetValue(obj, info.GetValue(fi.Name, fi.FieldType));
}
}
return obj;
}
#endregion #region ISurrogateSelector / 实现
/// <summary>
/// ChainSelector
/// </summary>
public void ChainSelector(ISurrogateSelector selector)
{
this._nextSelector = selector;
} /// <summary>
/// GetNextSelector
/// </summary>
public ISurrogateSelector GetNextSelector()
{
return _nextSelector;
} /// <summary>
/// GetSurrogate
/// </summary>
public ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
{
if (IsKnownType(type))
{
selector = null;
return null;
}
else if (type.IsClass || type.IsValueType)
{
selector = this;
return this;
}
else
{
selector = null;
return null;
}
}
#endregion #region 私有方法
/// <summary>
/// 是否为已知类型 / String,Primitive,Serializable
/// </summary>
private bool IsKnownType(Type type)
{
return type == typeof(string) || type.IsPrimitive || type.IsSerializable;
} /// <summary>
/// 是否为可空类型
/// </summary>
private bool IsNullableType(Type type)
{
if (type.IsGenericType)
{
return type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
return false;
} /// <summary>
/// GetFirstArgumentOfGenericType
/// </summary>
private Type GetFirstArgumentOfGenericType(Type type)
{
return type.GetGenericArguments()[];
}
#endregion
}
NonSerialiazableTypeSurrogateSelector.cs
扩展类 ObjectMethodExtensions :
public static class ObjectMethodExtensions
{
/// <summary>
/// 深度复制 (值类型/包装类型/引用类型/序列化/非序列化/标识序列化/非标识序列化,皆可深度复制)
/// </summary>
public static T DeepClone<T>(this T obj)
{
var result = default(T);
try
{
IFormatter formatter = new BinaryFormatter();
formatter.SurrogateSelector = new SurrogateSelector();
formatter.SurrogateSelector.ChainSelector(new NonSerialiazableTypeSurrogateSelector());
var ms = new MemoryStream();
formatter.Serialize(ms, obj);
ms.Position = ;
result = (T)formatter.Deserialize(ms);
}
catch (Exception ex)
{
throw new Exception("方法:DeepClone<T>(this T obj)出错.", ex);
}
return result;
}
}
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 周二
【Stack Overflow -- 原创加工、原创整理、生产实战】-- 深度复制的更多相关文章
- [SQL SERVER系列]工作经常使用的SQL整理,实战篇(一)[原创]
工作经常使用的SQL整理,实战篇,地址一览: 工作经常使用的SQL整理,实战篇(一) 工作经常使用的SQL整理,实战篇(二) 工作经常使用的SQL整理,实战篇(三) 目录概览: 1.数据库 2.表 3 ...
- [SQL SERVER系列]工作经常使用的SQL整理,实战篇(三)[原创]
工作经常使用的SQL整理,实战篇,地址一览: 工作经常使用的SQL整理,实战篇(一) 工作经常使用的SQL整理,实战篇(二) 工作经常使用的SQL整理,实战篇(三) 接着本系列前面两篇继续讨论. 有时 ...
- [SQL SERVER系列]工作经常使用的SQL整理,实战篇(二)[原创]
工作经常使用的SQL整理,实战篇,地址一览: 工作经常使用的SQL整理,实战篇(一) 工作经常使用的SQL整理,实战篇(二) 工作经常使用的SQL整理,实战篇(三) 接着上一篇“工作经常使用的SQL整 ...
- [原创].NET 业务框架开发实战之十 第一阶段总结,深入浅出,水到渠成(后篇)
原文:[原创].NET 业务框架开发实战之十 第一阶段总结,深入浅出,水到渠成(后篇) .NET 业务框架开发实战之十 第一阶段总结,深入浅出,水到渠成(后篇) 前言:接着上篇来. 系列文章链接: [ ...
- [原创].NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略
原文:[原创].NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略 .NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略 前言:之前的讨论一直关注在怎么从D ...
- [原创].NET 业务框架开发实战之八 业务层Mapping的选择策略
原文:[原创].NET 业务框架开发实战之八 业务层Mapping的选择策略 .NET 业务框架开发实战之八 业务层Mapping的选择策略 前言:在上一篇文章中提到了mapping,感觉很像在重新实 ...
- [原创].NET 业务框架开发实战之七 业务层初步构想
原文:[原创].NET 业务框架开发实战之七 业务层初步构想 .NET 业务框架开发实战之七 业务层初步构想 前言:本篇主要讲述如何把DAL和BLL衔接起来. 本篇议题如下: 1. DAL ...
- [原创].NET 业务框架开发实战之六 DAL的重构
原文:[原创].NET 业务框架开发实战之六 DAL的重构 .NET 业务框架开发实战之六 DAL的重构 前言:其实这个系列还是之前的".NET 分布式架构开发实战 ",之所以改了 ...
- [原创].NET 分布式架构开发实战五 Framework改进篇
原文:[原创].NET 分布式架构开发实战五 Framework改进篇 .NET 分布式架构开发实战五 Framework改进篇 前言:本来打算这篇文章来写DAL的重构的,现在计划有点改变.之前的文章 ...
随机推荐
- XInput和DirectInput
原文链接:https://msdn.microsoft.com/en-us/library/windows/desktop/ee417014(v=vs.85).aspx XInput是一个允许应用从W ...
- 微信第三方登录(原生)demo
在一家ecstore二开公司有一段时间了,公司希望往自己研发产品上面走,一直在培养新人. 最近要自己去微信登录,自己就在ectore的框架基础上,写的原生微信第三方登录以此来熟悉微信第三方登录,在 ...
- dede系统自定义变量删除方法
之前添加了个联系电话的系统变量,忘记写描述,结果就显示个冒号,很难看.这样的就要删除了重来,那么织梦怎么删除添加的变量呢?其实很简单.两种方法: 第一种:执行SQL语句.在织梦后台执行-系统-SQL命 ...
- NLTK学习笔记(四):自然语言处理的一些算法研究
自然语言处理中算法设计有两大部分:分而治之 和 转化 思想.一个是将大问题简化为小问题,另一个是将问题抽象化,向向已知转化.前者的例子:归并排序:后者的例子:判断相邻元素是否相同(与排序). 这次总结 ...
- 提高java编程质量 - (四)i++ 和 ++i 探究原理
先看一个例子: package com.test; public class AutoIncrement { public static void main(String[] args) { int ...
- Dalvik详解
整理自百度百科 Dalvik Dalvik是Google公司自己设计用于Android平台的Java虚拟机.Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一 ...
- ZooKeeper数据结构
Time in ZooKeeper ZooKeeper跟踪时间的多种方式 1)Zxid:每个ZooKeeper状态变化将会接收到一个zxid(ZooKeeper Transaction Id)的时间戳 ...
- ue4玄学画面设置实现
pc端项目临近发布之时,免不了向玩家提供一些自订选项,以适应各自的习惯和机能,画面设置就是必要的一环. 主要的画面选项有: 1.全屏/窗口化 2.分辨率 3.视野距离 4.抗锯齿 5.后期处理 6.阴 ...
- 重温Android中的消息机制
引入: 提到Android中的消息机制,大家应该都不陌生,我们在开发中不可避免的要和它打交道.从我们开发的角度来看,Handler是Android消息机制的上层接口.我们在平时的开发中只需要和Hand ...
- ios在Xcode里关于图片的权限设置
<key>NSPhotoLibraryUsageDescription</key> <string>This app requires access to the ...