【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的重构的,现在计划有点改变.之前的文章 ...
随机推荐
- Unity 遮罩 点击panel以外的位置,panel关闭
public Class Panel_ATMRechage : IPanel{ private Dictionary<string,UISprite>mSprites; } protect ...
- 【试验局】ReentrantLock中非公平锁与公平锁的性能测试
硬件环境: CPU:AMD Phenom(tm) II X4 955 Processor Memory:8G SSD(128G):/ HDD(1T):/home/ 软件环境: OS:Ubuntu14. ...
- php回调函数的使用
1.array_map — 将回调函数作用到给定数组的单元上 参数:array array_map ( callable $callback , array $arr1 [, array $... ] ...
- 学习css3中的动画
css animations 主要有两块构成,那么是哪两块呢? keyframes : 定义了什么阶段展示什么样的动画 animation 属性 :把动画挂载到一个具体的dom上,并且定义如何动起来: ...
- mysql5.6创建新用户并给授权指定的数据库权限
一.环境: CentOS 6.8 mysql 5.6 二.背景 给外包的工作人员提供我司某台服务器的 mysql 中某个数据库的访问权限. 之所以要做限制,是防止他们对我司其他的数据库非法进行操作. ...
- 分布式锁2 Java非常用技术方案探讨之ZooKeeper
前言: 由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.以自己结合实际工作中的一些经验和网上看到的一些资料 ...
- java学习——平台的安装与部署
Java 平台安装与部署 jre,jdk安装与部署 1)jre,jdk安装过程(略) 2)部署过程 新建(JAVA_HOME) 变量名:JAVA_HOME 变量值:E:\Program Files ( ...
- [codeforces113D]Museum
D. Museum time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard input ...
- [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现
NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...
- 关于MyEclipse修改项目名称后,部署到tomcat显示旧的项目名称
问题:用Myeclipse部署项目的时候, 出现部署到tomcat下的项目是之前的项目,而不是当前的项目. 解决方案:工程名->右键->Properties->MyEcl ...