zoukankan      html  css  js  c++  java
  • .NET的堆和栈03,引用类型对象拷贝以及内存分配

    在" .NET的堆和栈01,基本概念、值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配。我们知道:当执行一个方法的时候,值类型实例会在"栈"上分配内存,而引用类型实例会在"堆"上分配内存,当方法执行完毕,"栈"上的实例由操作系统自动释放,"堆"上的实例由.NET Framework的GC进行回收。


    在" .NET的堆和栈02,值类型和引用类型参数传递以及内存分配"中,我们了解了值类型参数和引用类型参数在传递时的内存分配情况。


    而本篇的重点要放在:引用类型对象拷贝以及内存分配。

    主要包括:
    ■  引用类型对象拷贝 成员都是值类型
    ■  引用类型对象拷贝 包含引用类型成员

      引用类型对象拷贝 成员都是值类型

    public struct Shoe{
                   public string Color;
               }
     
               public class Dude
               {
                    public string Name;
                    public Shoe RightShoe;
                    public Shoe LeftShoe;
     
                    public Dude CopyDude()
                    {
                         Dude newPerson = new Dude();
                         newPerson.Name = Name;
                         newPerson.LeftShoe = LeftShoe;
                         newPerson.RightShoe = RightShoe;
     
                         return newPerson;
                    }
     
                    public override string ToString()
                    {
                         return (Name + " : Dude!, I have a " + RightShoe.Color  +
                             " shoe on my right foot, and a " +
                              LeftShoe.Color + " on my left foot.");
                    }
     
               }
    
               public static void Main()
               {
                      Dude Bill = new Dude();
                      Bill.Name = "Bill";
                      Bill.LeftShoe = new Shoe();
                      Bill.RightShoe = new Shoe();
                      Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";
     
                      Dude Ted =  Bill.CopyDude();
                      Ted.Name = "Ted";
                      Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";
     
                      Console.WriteLine(Bill.ToString());
                      Console.WriteLine(Ted.ToString());            
               }

    输出结果:
    Bill : Dude!, I have a Red shoe on my right foot, and a Red on my left foot
    Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

    以上,当引用类型的属性、成员都是值类型的时候,拷贝是完全拷贝。

    16

      引用类型对象拷贝 包含引用类型成员

    把Shoe由struct值类型改成引用类型class。

    public class Shoe{
                   public string Color;
               }

    再次运行,输出结果:
    Bill : Dude!, I have a Red shoe on my right foot, and a Red on my left foot
    Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

    当Dude类包含引用类型属性Shoe的时候,在托管堆上的情况是这样的:
    17  

    拷贝后,2个Dude的Shoe类型的属性指向了同一个托管堆内的Shoe实例,改变Shoe的值会同时影响到2个Dude。


    很显然,这不是我们期望的完全拷贝,如何做到完全拷贝呢?
    --实现ICloneable接口       

    ICloneable接口的Clone()方法,允许我们在拷贝的时候,进行一些自定义设置。

    让引用类Shoe实现ICloneable接口。

    public class Shoe : ICloneable
                 {
                      public string Color;
     
                      public object Clone()
                      {
                          Shoe newShoe = new Shoe();
                          newShoe.Color = Color.Clone() as string;
                          return newShoe;
                      }
                 }


    以上,Shoe的string类型属性Color之所以可以使用Color.Clone()方法,是因为string也实现了ICloneable接口;又由于Clone()返回类型是object,所以,在使用Color.Clone()方法之后,需要把object转换成string类型。


    现在,在Dude类的CopyDude()方法中,当拷贝Shoe类型属性的时候,就可以使用Shoe独有的拷贝方法Clone()。

    public Dude CopyDude()
                    {
                        Dude newPerson = new Dude();
                         newPerson.Name = Name;
                         newPerson.LeftShoe = LeftShoe.Clone() as Shoe;
                         newPerson.RightShoe = RightShoe.Clone() as Shoe;
     
                         return newPerson;
                    }

    客户端程序。

    public static void Main()
               {
                      Dude Bill = new Dude();
                      Bill.Name = "Bill";
                      Bill.LeftShoe = new Shoe();
                      Bill.RightShoe = new Shoe();
                      Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";
     
                      Dude Ted =  Bill.CopyDude();
                      Ted.Name = "Ted";
                      Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";
     
                      Console.WriteLine(Bill.ToString());
                      Console.WriteLine(Ted.ToString());            
     
               }

    输出结果:  
    Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot
    Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot  

     

    这正是我们期望的完全拷贝!

    完全拷贝,托管堆上的情况是这样的:
    18

    当然也可以让同时包含值类型和引用类型成员,同时需要拷贝的类实现ICloneable接口。

    public class Dude: ICloneable
               {
                    public string Name;
                    public Shoe RightShoe;
                    public Shoe LeftShoe;
     
                    public override string ToString()
                    {
                         return (Name + " : Dude!, I have a " + RightShoe.Color  +
                             " shoe on my right foot, and a " +
                              LeftShoe.Color + " on my left foot.");
                        }
                      #region ICloneable Members
     
                      public object Clone()
                      {
                           Dude newPerson = new Dude();
                           newPerson.Name = Name.Clone() as string;
                           newPerson.LeftShoe = LeftShoe.Clone() as Shoe;
                           newPerson.RightShoe = RightShoe.Clone() as Shoe;
     
                           return newPerson;
                      }
     
                      #endregion
                 }

    客户端调用。

    public static void Main()
               {
                   Class1 pgm = new Class1();
     
                      Dude Bill = new Dude();
                      Bill.Name = "Bill";
                      Bill.LeftShoe = new Shoe();
                      Bill.RightShoe = new Shoe();
                      Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";
     
                      Dude Ted =  Bill.Clone() as Dude;
                      Ted.Name = "Ted";
                      Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";
     
                      Console.WriteLine(Bill.ToString());
                      Console.WriteLine(Ted.ToString());            
     
               }

    输出结果: 
    Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot.
    Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot.

    也是我们期望的完全拷贝!

    参考资料:
    C# Heap(ing) Vs Stack(ing) in .NET: Part III

    ".NET的堆和栈"系列包括:

    .NET的堆和栈01,基本概念、值类型内存分配

    .NET的堆和栈02,值类型和引用类型参数传递以及内存分配

    .NET的堆和栈03,引用类型对象拷贝以及内存分配

    .NET的堆和栈04,对托管和非托管资源的垃圾回收以及内存分配

  • 相关阅读:
    自动化运维与Saltstack
    keepalived+nginx 高可用集群
    Nginx集群(负载均衡)
    Nginx优化
    Nginx管理(一)
    业务环境、测试、上线逻辑
    服务器部署逻辑
    python面试题——爬虫相关
    springmvc文件上传
    springmvc入门
  • 原文地址:https://www.cnblogs.com/darrenji/p/3848393.html
Copyright © 2011-2022 走看看