浅拷贝:引用成员在被拷贝时,仅被复制原对象中引用成员的地址引用到新生对象,使用复制后的新对象、
若更改引用成员内的值可能会影响源对象
深拷贝:引用成员在被拷贝时,深入拷贝所有引用成员,而不是拷贝地址引用那样简单、新对象中包含的
所有成员、全部是新生对象在使用复制后的新对象不会影响源对象
浅拷贝在.NET中通常使用,System::Object::MemberwiseClone 直接进行快速拷贝、
<__DynamicallyInvokable(), SecuritySafeCritical()>
<MethodImpl(MethodImplOptions.InternalCall)>
Protected Function MemberwiseClone() As Object
下面是一个用于被序列化复制的类,“Deep Cory 深拷贝”、“Shallow Copy 浅拷贝”
需要被序列化的类,一定需要在类的顶部添加上<Serializable>特性 否则无法使用
如果不允许成员被序列化,应该在成员上方添加<NonSerialized>特性即可、
<Serializable>
Public Class DeepCopy
Private mValue As Integer
Public Property Value As Integer
Get
Return Me.mValue
End Get
Set(value As Integer)
Me.mValue = value
End Set
End Property
End Class
下面的代码主要是一个调用测试被序列化复制后修改成员中的值是否会影响源对象的成员
Sub Main()
Dim x = New DeepCopy()
x.Value = 250
Dim y As DeepCopy = Clone(x)
y.Value = 100
Console.WriteLine("X={0}, Y={1}", x.Value, y.Value)
Console.ReadKey(False)
End Sub
即使是浅拷贝上面的代码也不会影响源对象中成员,我在上面提到只有引用成员会被影响
而值类型成员不会相互影响、
浅拷贝引用单个引用成员指针依旧需要消耗足足4~8个字节、受处理器与开发平台制约
Public Function Clone(ByVal obj) As Object
Using ms As MemoryStream = New MemoryStream()
Dim fm = New BinaryFormatter()
fm.Serialize(ms, obj)
ms.Seek(0, SeekOrigin.Begin)
Return fm.Deserialize(ms)
End Using
End Function
上面是序列化深度复制的一个代码,创建内存流对象 MemoryStream 且创建
二进制序列化对象BinaryFormatter
BinaryFormatter::Serialize // 序列化
BinaryFormatter::Deserialize // 反序列化
把对象序列化后,Stream::Seek在结束位置,我们需要移动位置到流的开始处
才可以反序列化对象 否则会产生错误
Public Function IL_Clone(ByVal obj) As Object
Dim dm = New DynamicMethod("Clone", GetType(Object), {GetType(Object)})
Dim il = dm.GetILGenerator()
Dim il_0033 = il.DefineLabel()
Dim il_DE84 = il.DeclareLocal(GetType(MemoryStream))
Dim il_FA10 = il.DeclareLocal(GetType(BinaryFormatter))
Dim il_BCC2 = il.DeclareLocal(GetType(Object))
Dim iL_CS10 = il.DeclareLocal(GetType(Object))
il.Emit(OpCodes.Newobj, GetType(MemoryStream).GetConstructor({}))
il.Emit(OpCodes.Stloc_0)
il.Emit(OpCodes.Newobj, GetType(BinaryFormatter).GetConstructor({}))
il.Emit(OpCodes.Stloc_1)
il.Emit(OpCodes.Ldloc_1)
il.Emit(OpCodes.Ldloc_0)
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Callvirt, GetType(BinaryFormatter).GetMethod("Serialize", {GetType(MemoryStream), GetType(Object)}))
il.Emit(OpCodes.Ldloc_0)
il.Emit(OpCodes.Ldc_I4_0)
il.Emit(OpCodes.Conv_I8)
il.Emit(OpCodes.Ldc_I4_0)
il.Emit(OpCodes.Callvirt, GetType(MemoryStream).GetMethod("Seek", {GetType(Int64), GetType(SeekOrigin)}))
il.Emit(OpCodes.Pop)
il.Emit(OpCodes.Ldloc_1)
il.Emit(OpCodes.Ldloc_0)
il.Emit(OpCodes.Callvirt, GetType(BinaryFormatter).GetMethod("Deserialize", {GetType(MemoryStream)}))
il.Emit(OpCodes.Stloc_2)
il.Emit(OpCodes.Ldloc_0)
il.Emit(OpCodes.Callvirt, GetType(MemoryStream).GetMethod("Close", {}))
il.Emit(OpCodes.Ldloc_2)
il.Emit(OpCodes.Stloc_3)
il.Emit(OpCodes.Br_S, il_0033)
il.MarkLabel(il_0033)
il.Emit(OpCodes.Ldloc_3)
il.Emit(OpCodes.Ret)
Return dm.Invoke(dm, {obj})
End Function
上面是通过内嵌IL代码,实现对象的深拷贝 本质上是上上面代码的一个
机器写法 功能是相同的 做法也是相同的 只是一个调用Using一个Close
差异性并不是很大 依赖的命名空间
Imports System
Imports System.IO
Imports System.Reflection.Emit
Imports System.Runtime.Serialization.Formatters.Binary