【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的重构的,现在计划有点改变.之前的文章 ...
随机推荐
- Python爬虫01——第一个小爬虫
Python小爬虫——贴吧图片的爬取 在对Python有了一定的基础学习后,进行贴吧图片抓取小程序的编写. 目标: 首先肯定要实现图片抓取这个基本功能 然后实现对用户所给的链接进行抓取 最后要有一定的 ...
- Spark踩坑记——从RDD看集群调度
[TOC] 前言 在Spark的使用中,性能的调优配置过程中,查阅了很多资料,之前自己总结过两篇小博文Spark踩坑记--初试和Spark踩坑记--数据库(Hbase+Mysql),第一篇概况的归纳了 ...
- java 与操作系统进程同步问题(二)————经典消费者生产者问题
http://www.cnblogs.com/zyp4614/p/6033757.html (java 与操作系统进程同步问题(一)----互斥问题) 今天写的是最经典的生产者消费者问题,最简单的版本 ...
- JVM学习笔记三:垃圾收集器与内存分配策略
内存回收与分配重点关注的是堆内存和方法区内存(程序计数器占用小,虚拟机栈和本地方法栈随线程有相同的生命周期). 一.判断对象是否存活? 1. 引用计数算法 优势:实现简单,效率高. 致命缺陷:无法解决 ...
- Libevent源码分析—event, event_base
event和event_base是libevent的两个核心结构体,分别是反应堆模式中的Event和Reactor.源码分别位于event.h和event-internal.h中 1.event: s ...
- 03 编译安装apache的简易配置
1.监听端口,默认为80,在主配置文件 /etc/httpd24/httpd.conf中可以更改 2.持久连接 Include /etc/httpd24/extra/httpd-default.con ...
- HTML输入框只能输入数字或数字字母组合
JS判断只能是数字和小数点 1.文本框只能输入数字代码(小数点也不能输入) <input onkeyup="this.value=this.value.replace(/\D/g,'' ...
- WEB前端:浏览器(IE+Chrome+Firefox)常见兼容问题处理--02
兼容问题目录 8.IE6不支持固定定位 9.IE6下前面元素浮动,后面元素不浮动后他们之间会有间隙 10.IE6下双边距问题 11.IE67下父级有边框,子级有margin的话会不起作用 12.IE6 ...
- webApi签名验证
还是一如既往先上结构图如下: 上一讲说明了redis,也谢谢心态的建议.这里经过改进后的redis的地址 当然这里是加密了的,具体实现如下图: 这里提供的解密. 先把加密解密的帮助类放上来. usin ...
- 多线程异步编程示例和实践-Thread和ThreadPool
说到多线程异步编程,总会说起Thread.ThreadPool.Task.TPL这一系列的技术.总结整理了一版编程示例和实践,分享给大家. 先从Thread和ThreadPool说起: 1. 创建并启 ...