腾讯前端实习被问了这个问题,我就答了序列化的方式,然后很明显面试官不大满意,当然挂了的原因比较多,我慢慢总结积累一下:
首先要明确拷贝产生的结果都是reference type的,本质上还是指向一个对象(毕竟primitive type不需要)
所以深拷贝和浅拷贝的区别,就是拷贝这个reference指向的对象是不是之前的。
有以下两种方式,更推荐第一种:
1 泛型+反射: https://www.cnblogs.com/TheBob/p/9414014.html
/* 利用反射实现深拷贝*/
public static object DeepCopy(object _object)
{
Type T = _object.GetType();
object o = Activator.CreateInstance(T);
PropertyInfo[] PI = T.GetProperties();
for (int i = 0; i < PI.Length; i++)
{
PropertyInfo P = PI[i];
P.SetValue(o, P.GetValue(_object));
}
return o;
}
这种我觉得比较好,要理解这个方式首先复习一下反射的定义:
反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外 我还可以直接创建对象,即使这个对象的类型在编译时还不知道。可以实现从对象的外部来了解对象(或程序集)内部结构的功能,哪怕你不知道这个对象(或程序集)是个什么东西,另外.NET中的反射还可以运态创建出对象并执行它其中的方法。
为什么要用反射呢? 举个最简单的例子,当你在VS的设计器里拖入一个控件后,设计器会通过反射获取这个控件的属性,并提供给你进行设置, 设计器在做的时候,根本不可能预知将来有什么控件会被你拖入进去,所以要用反射。
所以反射看起来是主要被用于处理一些不可预知的情况,你不知道你要处理啥,比如说我当时学windows用到了反射来处理COM组件。
Type type = Type.GetType("类的完全限定名");
dynamic obj = type.Assembly.CreateInstance(type);
// 获取COM的类
public static System.Type t = Type.GetTypeFromProgID("CreateCOM.Class1");
public static dynamic o = Activator.CreateInstance(t);
这样的好处在于,它消除了模块之间的耦合,便于动态接口调用,在一些灵活的系统里面比较常用。
说回我们的主题,反射和泛型来实现深拷贝怎么做?
- 首先我们应该获取传入参数的那个对象的类型,也就是反射的GetType()
- 接下来Activator.CreateInstance(T); 用类型创建新拷贝的对象
- PropertyInfo[] PI = T.GetProperties(); 这里使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
- 接下来用Property的SetValue和GetValue来给新对象属性逐个赋值
- 大功告成,返回新对象就行
所以思路很清晰,调用的时候 Test b = (Test)DeepCopy(a); 泛型把object转回来就行
总的来说我觉得这是一种比较简单直接也好理解的方法
2 二进制流的方式(序列化)
/// 深拷贝 【不建议使用二进制流方法,此方法即使在类前面加了可序列化标志,调用该方法时也会报未序列化错误】,推荐使用反射方式
public object DeepCopy()
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
return (InvoiceDetailResponse)bFormatter.Deserialize(stream);
}
}
Emmmm我虽然当时回答这种,但是我其实并不懂.......可能确实这种方式也不大合适
另外我看有博客说用struct 代替class,或者一个一个赋值之类的,这些方式都有一些局限性,个人感觉第一种采取反射加泛型的方式是最好的。
补充:
.net提供了一个ICloneable接口,该接口下有一个Clone()方法,你可以实现它用来实现你自己的克隆方式,比如深克隆或是浅克隆,MemberwiseClone()是object类中的一个方法,用来实现类的浅克隆
比如浅拷贝的实现可以直接调用:当然这和直接=有啥区别我也不懂:( 欢迎大佬指点
public object ShallowCopy()
{
return this.MemberwiseClone();
}