NET的深复制方法(以C#语言为例)_第1页
NET的深复制方法(以C#语言为例)_第2页
NET的深复制方法(以C#语言为例)_第3页
NET的深复制方法(以C#语言为例)_第4页
NET的深复制方法(以C#语言为例)_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、NET的深复制方法(以C#语言为例)深复制需要将对象实例中字段引用的对象也进行复制,在平时的编程工作中经常要用到这种复制方式,下面以c#为例来演示一下方法。很多时候我们复制一个对象实例A到实例B,在用实例B去做其他事情的时候,会对实例B进行修改,为保证对B的修改不会影响到A的正常使用,就需要使用到深复制。 我在网上搜到一些深复制的方法,同时写了几组例子对这些方法进行测试。 我的操作系统版本为Win7旗舰版,.NET Framework版本是4.5 测试程序 我建了一个C#窗体应用程序(Winform),其主窗口FormMain的Load函数内容如下:private void FormMain_

2、Load(object sender, EventArgs e) /测试1:深度复制 自定义类 try Console.WriteLine("= 深度复制 自定义类 ="); TestClass test1 = new TestClass(); test1.a = 10; test1.b = "hello world!" test1.c = new string "x", "y", "z" ; TestClass test2 = new TestClass(); test2.a = 11; te

3、st2.b = "hello world2!" test2.c = new string "i", "j", "k" ; test1.d = test2; Console.WriteLine("-test1_start-"); Console.WriteLine(test1); Console.WriteLine("-test1_end-"); TestClass test3 = (TestClass)DataManHelper.DeepCopyObject(test1);

4、Console.WriteLine("-test3_start-"); Console.WriteLine(test3); Console.WriteLine("-test3_end-"); catch (Exception ex) Console.WriteLine(ex.ToString(); /测试2:深度复制 可序列化的自定义类try Console.WriteLine("= 深度复制 可序列化的自定义类 ="); TestClassWithS test1 = new TestClassWithS(); test1.a = 1

5、0; test1.b = "hello world!" test1.c = new string "x", "y", "z" ; TestClassWithS test2 = new TestClassWithS(); test2.a = 11; test2.b = "hello world2!" test2.c = new string "i", "j", "k" ; test1.d = test2; Console.WriteLin

6、e("-test1_start-"); Console.WriteLine(test1); Console.WriteLine("-test1_end-"); TestClassWithS test3 = (TestClassWithS)DataManHelper.DeepCopyObject(test1); Console.WriteLine("-test3_start-"); Console.WriteLine(test3); Console.WriteLine("-test3_end-");catch (Ex

7、ception ex) Console.WriteLine(ex.ToString(); /测试3:深度复制 DataTabletry Console.WriteLine("= 深度复制 DataTable ="); DataTable dtKirov = new DataTable("TestTable"); dtKirov.Columns.Add("Col1"); dtKirov.Columns.Add("Col2"); dtKirov.Columns.Add("Col3"); dtKiro

8、v.Rows.Add("1-1", "1-2", "1-3"); dtKirov.Rows.Add("2-1", "2-2", "2-3"); dtKirov.Rows.Add("3-1", "3-2", "3-3"); Console.WriteLine("= 复制前 ="); for (int i = 0; i < dtKirov.Columns.Count; i+) Console.W

9、rite(dtKirov.Columnsi.ColumnName + "t"); Console.WriteLine("n-"); for (int i = 0; i < dtKirov.Columns.Count; i+) for (int j = 0; j < dtKirov.Rows.Count; j+) Console.Write(dtKirov.Rowsij.ToString() + "t"); Console.WriteLine(); Console.WriteLine(); DataTable dtDread

10、Nought = (DataTable)DataManHelper.DeepCopyObject(dtKirov); Console.WriteLine("= 复制后 ="); for (int i = 0; i < dtDreadNought.Columns.Count; i+) Console.Write(dtDreadNought.Columnsi.ColumnName + "t"); Console.WriteLine("n-"); for (int i = 0; i < dtDreadNought.Columns

11、.Count; i+) for (int j = 0; j < dtDreadNought.Rows.Count; j+) Console.Write(dtDreadNought.Rowsij.ToString() + "t"); Console.WriteLine(); Console.WriteLine();catch (Exception ex) Console.WriteLine(ex.ToString(); /测试4:深度复制 TextBoxtry Console.WriteLine("= 深度复制 TextBox ="); txtTes

12、t.Text = "1234" Console.WriteLine("复制前:" + txtTest.Text); TextBox txtTmp = new TextBox(); txtTmp = (TextBox)DataManHelper.DeepCopyObject(txtTest); Console.WriteLine("复制后:" + txtTmp.Text);catch (Exception ex) Console.WriteLine(ex.ToString(); /测试5:深度复制 DataGridViewtry Con

13、sole.WriteLine("= 深度复制 DataGridView ="); DataGridView dgvTmp = new DataGridView(); dgvTmp = (DataGridView)DataManHelper.DeepCopyObject(dgvTest); catch (Exception ex) Console.WriteLine(ex.ToString(); 其中txtTest是一个测试用的TextBox,dgvTmp是一个测试用的DataGridView,TestClass是一个自定义类,TestClassWithS是添加了Serial

14、izable特性的TestClass类,它们的具体实现如下:using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace DataCopyTest public class TestClass public int a; public string b; public string c; public TestClass d; public override string ToString() string s = "a:" + a + "n

15、" if (b != null) s += "b:" + b + "n" if (c != null) foreach (string tmps in c) if (!string.IsNullOrWhiteSpace(tmps) s += "c:" + tmps + "n" if (d != null) s += d.ToString(); return s; /支持序列化的TestClass Serializable public class TestClassWithS public int a;

16、public string b; public string c; public TestClassWithS d; public override string ToString() string s = "a:" + a + "n" if (b != null) s += "b:" + b + "n" if (c != null) foreach (string tmps in c) if (!string.IsNullOrWhiteSpace(tmps) s += "c:" + tmps

17、+ "n" if (d != null) s += d.ToString(); return s; 我对每个搜来的深复制方法,都用了这五个类的实例进行深复制测试,这五个类的特征如下: I、对自定义类TestClass进行深复制测试 II、对自定义类TestClassWithS进行深复制测试,TestClassWithS是添加了Serializable特性的TestClass类 III、对DataTable进行深复制测试 IV、对控件TextBox进行深复制测试 V、对控件DataGridView进行深复制测试 我们通过实现方法DataManHelper.DeepCopyOb

18、ject来进行测试 测试深复制方法1 使用二进制流的序列化与反序列化深度复制对象public static object DeepCopyObject(object obj) BinaryFormatter Formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone); MemoryStream stream = new MemoryStream(); Formatter.Serialize(stream, obj); stream.Position = 0; object cl

19、onedObj = Formatter.Deserialize(stream); stream.Close(); return clonedObj; 五个场景的测试结果为: I、触发异常SerializationException,原因是该类不支持序列化 “System.Runtime.Serialization.SerializationException”类型的第一次机会异常在 mscorlib.dll 中发生 System.Runtime.Serialization.SerializationException: 程序集“DataCopyTest, Version=, Cu

20、lture=neutral, PublicKeyToken=null”中的类型“DataCopyTest.TestClass”未标记为可序列化。 在 System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) 在 System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) 在 System.Runtime.Ser

21、ialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter ob

22、jectWriter, SerializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, S“DataCopyTvsh

23、ost.exe”(托管(v4.0.30319): 已加载“C:WindowsMicrosoft.NetassemblyGAC_MSILSystem.Numericsv4.0__b77a5c561934e089System.Numerics.dll” erializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header inHeaders, _BinaryWriter serWriter, Boolean fChe

24、ck) 在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header headers, Boolean fCheck) 在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) 在 DataCopyTest.DataManHelper.D

25、eepCopyObject(Object obj) 位置 d:MyProgramsDataCopyTestDataCopyTestDataManHelper.cs:行号 24 在 DataCopyTest.FormMain.FormMain_Load(Object sender, EventArgs e) 位置 d:MyProgramsDataCopyTestDataCopyTestFormMain.cs:行号 37 II、可正常复制 () III、可正常复制 () IV、触发异常SerializationException,原因是该类不支持序列化 “System.Runtime.Serial

26、ization.SerializationException”类型的第一次机会异常在 mscorlib.dll 中发生 System.Runtime.Serialization.SerializationException: 程序集“System.Windows.Forms, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089”中的类型“System.Windows.Forms.TextBox”未标记为可序列化。 在 System.Runtime.Serialization.FormatterServices.In

27、ternalGetSerializableMembers(RuntimeType type) 在 System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectIn

28、fo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object ob

29、j, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header inHeaders, _Binar

30、yWriter serWriter, Boolean fCheck) 在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header headers, Boolean fCheck) 在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)

31、 在 DataCopyTest.DataManHelper.DeepCopyObject(Object obj) 位置 d:MyProgramsDataCopyTestDataCopyTestDataManHelper.cs:行号 24 在 DataCopyTest.FormMain.FormMain_Load(Object sender, EventArgs e) 位置 d:MyProgramsDataCopyTestDataCopyTestFormMain.cs:行号 128 V、触发异常SerializationException,原因是该类不支持序列化 “System.Runtime.

32、Serialization.SerializationException”类型的第一次机会异常在 mscorlib.dll 中发生 System.Runtime.Serialization.SerializationException: 程序集“System.Windows.Forms, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089”中的类型“System.Windows.Forms.DataGridView”未标记为可序列化。 在 System.Runtime.Serialization.Formatter

33、Services.InternalGetSerializableMembers(RuntimeType type) 在 System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 在 System.Runtime.Serialization.Formatters.Binary.Wr

34、iteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serializ

35、e(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header inHead

36、ers, _BinaryWriter serWriter, Boolean fCheck) 在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header headers, Boolean fCheck) 在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Ob

37、ject graph) 在 DataCopyTest.DataManHelper.DeepCopyObject(Object obj) 位置 d:MyProgramsDataCopyTestDataCopyTestDataManHelper.cs:行号 24 在 DataCopyTest.FormMain.FormMain_Load(Object sender, EventArgs e) 位置 d:MyProgramsDataCopyTestDataCopyTestFormMain.cs:行号 141 结论:利用序列化与反序列化到二进制流的方法深复制对象,只有在该对象支持Serializabl

38、e特性时才可使用 测试深复制方法2public static object DeepCopyObject(object obj) Type t = obj.GetType(); PropertyInfo properties = t.GetProperties(); Object p = t.InvokeMember("", System.Reflection.BindingFlags.CreateInstance, null, obj, null); foreach (PropertyInfo pi in properties) if (pi.CanWrite) obje

39、ct value = pi.GetValue(obj, null); pi.SetValue(p, value, null); return p; 五个场景的测试结果为: I、不会触发异常,但结果完全错误 II、不会触发异常,但结果完全错误 III、不会触发异常,但结果完全错误 IV、Text字段赋值结果正确,但其他内容不能保证 V、触发异常ArgumentOutOfRangeException、TargetInvocationException “System.ArgumentOutOfRangeException”类型的第一次机会异常在 System.Windows.Forms.dll 中

40、发生 “System.Reflection.TargetInvocationException”类型的第一次机会异常在 mscorlib.dll 中发生 System.Reflection.TargetInvocationException: 调用的目标发生了异常。 -> System.ArgumentOutOfRangeException: 指定的参数已超出有效值的范围。 参数名: value 在 System.Windows.Forms.DataGridView.set_FirstDisplayedScrollingColumnIndex(Int32 value) - 内部异常堆栈跟

41、踪的结尾 - 在 System.RuntimeMethodHandle.InvokeMethod(Object target, Object arguments, Signature sig, Boolean constructor) 在 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object parameters, Object arguments) 在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invo

42、keAttr, Binder binder, Object parameters, CultureInfo culture) 在 System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object index, CultureInfo culture) 在 System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object index

43、) 在 DataCopyTest.DataManHelper.DeepCopyObject(Object obj) 位置 d:MyProgramsDataCopyTestDataCopyTestDataManHelper.cs:行号 29 在 DataCopyTest.FormMain.FormMain_Load(Object sender, EventArgs e) 位置 d:MyProgramsDataCopyTestDataCopyTestFormMain.cs:行号 141 结论:使用这种方法进行所谓深复制,完全是自寻死路! 测试深复制方法3public static object D

44、eepCopyObject(object obj) if (obj != null) object result = Activator.CreateInstance(obj.GetType(); foreach (FieldInfo field in obj.GetType().GetFields() if (field.FieldType.GetInterface("IList", false) = null) field.SetValue(result, field.GetValue(obj); else IList listObject = (IList)field

45、.GetValue(result); if (listObject != null) foreach (object item in (IList)field.GetValue(obj) listObject.Add(DeepCopyObject(item); return result; else return null; 五个场景的测试结果为: I、可正常复制() II、可正常复制() III、未触发异常, 复制后DataTable无行列 IV、未触发异常,Text字段未赋值 V、未触发异常 结论:这个方法只适用于深复制具备简单结构的类(如类中只有基础字段、数组等),对于不支持序列化的对象

46、也可以进行深复制。 测试深复制方法4 这段代码来源同方法3public static object DeepCopyObject(object obj) if (obj = null) return null; Type type = obj.GetType(); if (type.IsValueType | type = typeof(string) return obj; else if (type.IsArray) Type elementType = Type.GetType( type.FullName.Replace("", string.Empty); var

47、 array = obj as Array; Array copied = Array.CreateInstance(elementType, array.Length); for (int i = 0; i < array.Length; i+) copied.SetValue(DeepCopyObject(array.GetValue(i), i); return Convert.ChangeType(copied, obj.GetType(); else if (type.IsClass) object toret = Activator.CreateInstance(obj.Ge

48、tType(); FieldInfo fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (FieldInfo field in fields) object fieldValue = field.GetValue(obj); if (fieldValue = null) continue; field.SetValue(toret, DeepCopyObject(fieldValue); return toret; else throw n

49、ew ArgumentException("Unknown type"); 五个场景的测试结果为: I、可正常复制() II、可正常复制() III、触发异常MissingMethodException “System.MissingMethodException”类型的第一次机会异常在 mscorlib.dll 中发生 System.MissingMethodException: 没有为该对象定义无参数的构造函数。 在 System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly,

50、 Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) 在 System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) 在 System.RuntimeType.CreateInstanceDefaultCtor(Bool

51、ean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) 在 System.Activator.CreateInstance(Type type, Boolean nonPublic) 在 System.Activator.CreateInstance(Type type) 在 DataCopyTest.DataManHelper.DeepCopyObject(Object obj) 位置 d:MyProgramsDataCopyTestDataCopyTestDataMan

52、Helper.cs:行号 45 在 DataCopyTest.DataManHelper.DeepCopyObject(Object obj) 位置 d:MyProgramsDataCopyTestDataCopyTestDataManHelper.cs:行号 53 在 DataCopyTest.FormMain.FormMain_Load(Object sender, EventArgs e) 位置 d:MyProgramsDataCopyTestDataCopyTestFormMain.cs:行号 99 IV、未触发异常,但Text字段也未赋值成功 V、触发异常MissingMethodE

53、xception “System.MissingMethodException”类型的第一次机会异常在 mscorlib.dll 中发生 System.MissingMethodException: 没有为该对象定义无参数的构造函数。 在 System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSe

54、curityCheck) 在 System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) 在 System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) 在 System.Activ

55、ator.CreateInstance(Type type, Boolean nonPublic) 在 System.Activator.CreateInstance(Type type) 在 DataCopyTest.DataManHelper.DeepCopyObject(Object obj) 位置 d:MyProgramsDataCopyTestDataCopyTestDataManHelper.cs:行号 45 在 DataCopyTest.DataManHelper.DeepCopyObject(Object obj) 位置 d:MyProgramsDataCopyTestDataCopyTestDataManHelpe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论