首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

【原创+探讨】对象的深层拷贝,该怎么处理

2012-01-24 
【原创+探讨】对象的深层拷贝原文在这里:http://blog.csdn.net/CsToD/archive/2009/07/29/4390600.aspx遇到

【原创+探讨】对象的深层拷贝
原文在这里:
http://blog.csdn.net/CsToD/archive/2009/07/29/4390600.aspx

遇到这么个问题,没有参考任何资料,自己想了个方法

对于自定义的一些简单类型还好,遇到.Net里一些复杂的类就无能为力了,不知道还有什么更好的方法。

class CsToD
{
  //基本思想是:一个对象所占据的内存空间,取决于它的实例字段(包括继承树上的私有实例字段)
  public T DeepCloneObject<T>(T obj) where T : class
  {
  //System.String类型似乎比较特殊,复制它的所有字段,并不能复制它本身
  //不过由于System.String的不可变性,即使指向同一对象,也无所谓
  //而且.NET里本来就用字符串池来维持
  if (obj == null || obj.GetType() == typeof(string))
  return obj;
  object newObj = null;
  try
  {
  //尝试调用默认构造函数
  newObj = Activator.CreateInstance(obj.GetType());
  }
  catch
  {
  //失败的话,只好枚举构造函数了
  foreach (ConstructorInfo ci in obj.GetType().GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
  {
  try
  {
  ParameterInfo[] pis = ci.GetParameters();
  object[] objs = new object[pis.Length];
  for (int i = 0; i < pis.Length; i++)
  {
  if (pis[i].ParameterType.IsValueType)
  objs[i] = Activator.CreateInstance(pis[i].ParameterType);
  else
  //参数类型可能是抽象类或接口,难以实例化
  //我能想到的就是枚举应用程序域里的程序集,找到实现了该抽象类或接口的类
  //但显然过于复杂了
  objs[i] = null;
  }
  newObj = ci.Invoke(objs);
  //无论调用哪个构造函数,只要成功就行了
  break;
  }
  catch
  {
  }
  }
  }
  foreach (FieldInfo fi in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
  {
  if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
  fi.SetValue(newObj, fi.GetValue(obj));
  else
  fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
  }
  //基类的私有实例字段在子类里检索不到,但它仍占据子类对象的内存空间
  Deep(newObj, obj);
  return (T)newObj;
  }

  //克隆继承树上的私有实例字段
  public void Deep(object newObj, object obj)
  {
  for (Type father = newObj.GetType().BaseType; father != typeof(object); father = father.BaseType)
  {
  foreach (FieldInfo fi in father.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
  {
  //只需要处理私有字段,因为非私有成员已经在子类处理过了
  if (fi.IsPrivate)
  {
  if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
  {
  fi.SetValue(newObj, fi.GetValue(obj));
  }
  else
  {
  fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
  }
  }
  }
  }
  }
}

写个代码来测试一下:

class Program
{
  static void Main()
  {
  Data3 data3 = new Data3();
  Data data = new Data(data3);
  data.PriValue = "Pri";


  data.Integer = 3;


  //修改cloneData对象,并未影响到data对象,说明克隆成功
  CsToD ctd = new CsToD();
  Data cloneData = ctd.DeepCloneObject(data);
  cloneData.Integer = 1000;
  cloneData.PriValue = "clone";
  cloneData.Value.D3String = "clonestr";
  Console.WriteLine(data.Integer + "<->" + cloneData.Integer);
  Console.WriteLine(data.PriValue + "<->" + cloneData.PriValue);
  Console.WriteLine(data.Value.D3String + "<->" + cloneData.Value.D3String);


  //而如果修改refData对象,data对象也被改变,说明是同一对象
  Data refData = data;
  refData.Integer = 555;
  refData.PriValue = "ref";
  refData.Value.D3String = "refstr";
  Console.WriteLine(data.Integer + "<->" + refData.Integer);
  Console.WriteLine(data.PriValue + "<->" + refData.PriValue);
  Console.WriteLine(data.Value.D3String + "<->" + refData.Value.D3String);
  }
}
class Data:Data2
{
  public Data(Data3 value)
  {
  this.Value = value;
  }
  public Data() { }
  public Data3 Value;

}
class Data2
{
  public Data2(int value)
  {
  this.Integer = value;
  }
  public string PriValue
  {
  get
  {
  return priValue;
  }
  set
  {
  priValue = value;
  }
  }
  public Data2() { }
  public int Integer;
  private string priValue;
}
class Data3
{
  public Data3()
  {
  D3String = "D3";
  d3Integer = 3;
  }
  public string D3String;
  private int d3Integer;
}



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/CsToD/archive/2009/07/29/4390600.aspx

[解决办法]
顶这个...
[解决办法]
mark
[解决办法]
对于复杂的类我想去实现ICloneable接口来做比较好
[解决办法]
up
[解决办法]
我比较喜欢偷懒的方法,用序列化反序列化来做。
有个缺点,字段和类都必须是可序列化的~
[解决办法]
public class classClone : ICloneable
{

public string test = "";

#region ICloneable 成员

public object Clone()
{
//throw new NotImplementedException();
classClone classClone = new classClone();
classClone.test = this.test ;
return classClone;
}

#endregion
}
[解决办法]
up
[解决办法]
恩,如果是对存在类进行Clone的话,太过于复杂的,我觉得一个通用方法就可以深层Copy,难度是非常可观的,难点就在与new一个该类的实例,只要有无参构造函数的,还是相对来说比较简单的。有参数的构造函数,我觉得几乎就处理不了。
如果是说想在自己项目中用的话,除非对类有些规则,然后根据规则使用通用的深层Copy。
[解决办法]
试一试反射呢?在需要尝试拷贝的时候,使用反射读取当前对象的属性或字段类型,然后复制该字段值,如果当前分析的字段不是基础类型,则继续用递归处理


[解决办法]
做个记号,有空研究
[解决办法]
首先利用sourceObject.GetType()方法,得到sourceObject的类型objectType,然后调用静态方法Activator.CreateInstance(objectType)得到该类型的一个新的实例newObject,这个返回实例用一个object引用来提领。接下来,使用objectType.GetProperties()得到该类型所有的公共属性(get-set属性)。对于其中的每一个属性,如果其类型是C#语言内置类型,如int, string, double等,就将sourceObject对象中这个属性的值直接赋给新对象newObject的相同属性。由于不知道这个object的实际类型,因此无法将这个ojbect引用显式cast成为实际类型,从而也就不能直接调用这个公共属性的set方法,而需要通过InvokerMember()方法来调用。InvokerMember的功能很强大,主要参数有需要调用的成员方法名,该成员方法所属的对象引用,以及一个包括目标成员方法参数列表的object[]。如果该属性不是一个C#语言内置类型,而是一个自定义类对象的引用,则递归copyObject()方法自身,得到这个自定义对象的一个新实例,并将该实例的引用赋值给这个属性。如果该属性是一个数组,则通过for循环来执行上述过程。 

[解决办法]
一直想学习
[解决办法]
帮顶
[解决办法]

探讨
我比较喜欢偷懒的方法,用序列化反序列化来做。
有个缺点,字段和类都必须是可序列化的~

[解决办法]
[size=18px]
C# code
太厉害了~~~学习ing。。。
[解决办法]
帮顶吧
[解决办法]
如果要复制数组和嵌套类或结构,可以通过递归clone,只不过类的话需要点特殊处理,因为可能存在循环引用,所以在clone的时候需要保存已经clone过的对象防止重复clone。
[解决办法]
关注一下
[解决办法]
真的有点长
[解决办法]
mark
[解决办法]
MARK
[解决办法]
用object.MemberwiseClone()递归做clone应该也可以。

用序列化和反序列化做,最大的问题就是[NonSerialized]标签,如果打了就不好用了。
[解决办法]
MARK
[解决办法]
UP!
[解决办法]
学习

[解决办法]
up
[解决办法]
mark
[解决办法]
路过
[解决办法]
学习
[解决办法]
.
[解决办法]
还得深入去学习。
[解决办法]
有循环引用的时候会死循环的吧,例如:
C# code
public class Foo{  public Bar bar = new Bar(this);}public class Bar{  public Foo foo;  public Bar(Foo foo)  {    this.foo = foo;  }}//然后CloneFoo foo = new Foo();CsToD ctd = new CsToD();Foo cloneData = ctd.DeepCloneObject(foo);
[解决办法]
哎 比我强多了,看了感到悲哀
[解决办法]
值得 学习咯。。顶顶
------解决方案--------------------


up
[解决办法]
收藏了, 天亮了再看。
[解决办法]
收藏关注
[解决办法]
没得说,好
[解决办法]
收藏关注
[解决办法]
路过的
[解决办法]

探讨
1.你的语法是错误的

public class Foo
{
  public Bar bar = new Bar(this);
}
this从何而来?编译器错误

[解决办法]
还是觉得 ICloneable 比较方便
[解决办法]
差太多 飘过了
[解决办法]
duck
[解决办法]
你的图像看得我头好晕啊!
[解决办法]
说掉了:50楼的,你的图像看的我好晕啊!
[解决办法]
标记之。
[解决办法]
有道理
[解决办法]
能拷贝控件吗?
[解决办法]
UP!
[解决办法]
和治病一样,好的药方应该是没有副作用的.否则治好了感冒却得了肺癌.. 恐怖吧?

楼主的这种时间深层复制的方法,就算可是完全实现复制,但可知这样的副作用? 如果在实际项目中也这样实现,真是灾难来临也不知道, 没人看出来?
[解决办法]
深复制,浅复制
[解决办法]
学习
[解决办法]
探讨
引用:
1.你的语法是错误的

public class Foo
{
  public Bar bar = new Bar(this);
}
this从何而来?编译器错误

呃,写错了
我想表达的是
C# codepublicclass Foo
{public Bar bar;public Foo()
{
bar=new Bar(this);
}
}

[解决办法]
帮顶!!
[解决办法]
上一课
[解决办法]
不如序列化来得实用

只要实现个别自定义类的接口就行

.net不实现通用的深度克隆,也有考虑.
[解决办法]
探讨
不如序列化来得实用

只要实现个别自定义类的接口就行

.net不实现通用的深度克隆,也有考虑.

[解决办法]
探讨
引用:
不如序列化来得实用

只要实现个别自定义类的接口就行

.net不实现通用的深度克隆,也有考虑.


public class UserEntity
{
public string Name{get;set;}
public int ID{get;set;}
public UserEntity CreatedUser{get;set;}
}
你试试序列化这个。

[解决办法]
顶了~以后有空再学习~
[解决办法]


探讨
引用:
1.你的语法是错误的

public class Foo
{
  public Bar bar = new Bar(this);
}
this从何而来?编译器错误

呃,写错了
我想表达的是
C# codepublicclass Foo
{public Bar bar;public Foo()
{
bar=new Bar(this);
}
}

[解决办法]
还得深入去学习
[解决办法]
感觉自定义序列化很好用

热点排行