c#的System.ICloneable接口说明

System.ICloneable接口支持克隆,即用与现有实例相同的值创建类的新实例。msdn上的解释很简单,主要就是clone方法的实行,介绍深拷贝和浅拷贝,搞的很糊涂,那么到底是什么意思呢?看看下面的原理可能就会明白很多了。引自http://www.cnblogs.com/anderslly/archive/2007/04/08/implementingcloneabletype.html

原理

如果我们有两个值类型的变量,将其中一个变量的值赋给另一个,实际上会创建该值的一个副本,这个副本与原来的值没有什么关系——这意味着改变其中一个的值不会影响另一个变量的值。而如果是两个引用类型的变量,其中一个变量的值赋给另一个的话(不包括string类型,CLR会对其有特殊处理),并没有创建值的副本,而是使两个变量执行同一个对象——这意味着改变对象的值会同时影响两个变量。要真正地创建引用类型的副本,我们必须克隆(clone)变量指向的对象

实现ICloneable接口使一个类型成为可克隆的(cloneable),这需要提供Clone方法来提供该类型的对象的副本。Clone方法不接受任何参数,返回object类型的对象(不管是何种类型实现该接口)。所以我们获得副本后仍需要进行显式地转换。

实现ICloneable接口的方式取决于我们的类型的数据成员。如果类型仅包含值类型(int,byte等类型)和string类型的数据成员,我们只要在Clone方法中初始化一个新的对象,将其的数据成员设置为当前对象的各个成员的值即可。事实上,object类的 MemberwiseClone方法会自动完成该过程。

如果自定义类型包含引用类型的数据成员,必须考虑Clone方法是实现浅拷贝(shallow copy)还是深拷贝(deep copy)。浅拷贝是指副本对象中的引用类型的数据成员与源对象的数据成员指向相同的对象。而如果是深拷贝,则必须创建整个对象的结构,副本对象中的引用类型的数据成员与源对象的数据成员指向不同的对象。

浅拷贝是容易实现的,就是使用前面提到的MemberwiseClone方法。开发人员往往希望使用的类型能够实现深拷贝,但会发现这样的类型并不多。这种情况在System.Collections命名空间中尤其常见,这里面的类在其Clone方法中实现的都是浅拷贝。这么做主要出于两个原因:

  1. 创建一个大对象的副本对性能影响较大;
  2. 通用的集合类型可能会包含各种各样的对象,在这种情况下实现深拷贝并不可行,因为集合中的对象并非都是可克隆的,另外还存在循环引用的情况,这会让深拷贝过程陷入死循环。

对于强类型的集合情况有所不同,因为它包含的元素是可控制的,此时深拷贝变得有用,同时也是可行的。例如System.Xml.XmlNode在其Clone方法中实现了深拷贝。

另外,如果需要克隆一个未实现ICloneable接口却是可序列化的对象,通常可以通过序列化和反序列化来达到克隆的效果。但要小心,序列化过程不一定会序列化所以数据成员。

代码

下面的代码示例描述了克隆的各种方法。简单的Employee类仅仅包含string和int类型的成员,所以使用object类型的 MemberwiseClone方法创建副本。Team类的Clone方法实现了深拷贝,它包含了一个Employee对象的集合,同时Team类提供了一个私有的构造函数用以简化Clone方法的代码。构造函数的这种用法是简化克隆过程的一种常见方式。

public  class  Employee  ICloneable
{
        public  string  Name;
        public  string  Title;
        public  int  Age;

        //  Simple Emplyee constructor
        public  Employee( string  name,  string  title,  int  age)
        {
                Name  name;
                Title  title;
                Age  age;
        }

        public  object  Clone()
        {
                return  MemberwiseClone();
        }

        public  override  string  ToString()
        {
                return  string.Format("{0}  ({1})  Age  {2}",  Name,  Title,  Age);
        }
}

Team类代码:

public  class  Team  ICloneable
{
        public  List<Employee>  TeamMembers  new  List<Employee>();

        public  Team()
        {
        }

        private  Team(List<Employee>  members)
        {
                foreach  (Employee  in  members)
                {
                        TeamMembers.Add(e.Clone()  as  Employee);
                }
        }

        //  Adds an Employee object to the Team.
        public  void  AddMember(Employee  member)
        {
                TeamMembers.Add(member);
        }

        //  Override Object.ToString method to return string representation of the team.
        public  override  string  ToString()
        {
                StringBuilder  sb  new  StringBuilder();
                foreach  (Employee  in  TeamMembers)
                {
                        sb.AppendFormat("    {0}\r\n",  e);
                }

                return  sb.ToString();
        }

        //  Implementation of ICloneable.Clone.
        public  object  Clone()
        {
                return  new  Team( this.TeamMembers);

                //  the following code would create shallow copy of the team.
        
// return MemberwiseClone();
        }
}

测试代码:

//  Create the original team.
Team  team  new  Team();
team.AddMember( new  Employee("Anders",  "Developer",  26));
team.AddMember( new  Employee("Bill",  "Developer",  46));
team.AddMember( new  Employee("Steve",  "CEO",  36));

Team  clone  team.Clone()  as  Team;

//  Display the original team.
Console.WriteLine("Original  Team:");
Console.WriteLine(team);

//  Display the cloned team.
Console.WriteLine("Clone  Team:");
Console.WriteLine(clone);

//  Make changes.
Console.WriteLine("***  Make  change  to  original  team  ***");
Console.WriteLine(Environment.NewLine);
team.TeamMembers[0].Title  "PM";
team.TeamMembers[0].Age  30;

//  Display the original team.
Console.WriteLine("Original  Team:");
Console.WriteLine(team);

//  Display the cloned team.
Console.WriteLine("Clone  Team:");
Console.WriteLine(clone);
运行结果如下:


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值