搜索

查看: 3068|回复: 11

[ASP.NET] ASP.NET堆和栈三之引用类型对象拷贝和内存分配

[复制链接]
发表于 2023-5-4 11:32:42 | 显示全部楼层 |阅读模式
Editor 2023-5-4 11:32:42 3068 11 看全部
".NET的堆和栈"系列:
ASP.NET堆和栈一之基本概念和值类型内存分配
ASP.NET堆和栈二之值类型和引用类型参数传递和内存分配
ASP.NET堆和栈三之引用类型对象拷贝和内存分配
ASP.NET堆和栈四之对托管和非托管资源垃圾的回收和内存分配
在" ASP.NET堆和栈一之基本概念和值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配。我们知道:当执行一个方法的时候,值类型实例会在"栈"上分配内存,而引用类型实例会在"堆"上分配内存,当方法执行完毕,"栈"上的实例由操作系统自动释放,"堆"上的实例由.NET Framework的GC进行回收。
在" ASP.NET堆和栈二之值类型和引用类型参数传递和内存分配"中,我们了解了值类型参数和引用类型参数在传递时的内存分配情况。
而本篇的重点要放在:引用类型对象拷贝以及内存分配。
引用类型对象拷贝 成员都是值类型
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

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

202281395823811.png

202281395823811.png


引用类型对象拷贝 包含引用类型成员
把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的时候,在托管堆上的情况是这样的:

202281395823812.png

202281395823812.png


拷贝后,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  

这正是我们期望的完全拷贝!
完全拷贝,托管堆上的情况是这样的:

202281395823813.png

202281395823813.png


当然也可以让同时包含值类型和引用类型成员,同时需要拷贝的类实现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.

也是我们期望的完全拷贝!
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对知鸟论坛的支持。如果你想了解更多相关内容请查看下面相关链接
回复

使用道具 举报

发表于 2023-6-28 21:01:20 | 显示全部楼层
小妖花满楼满fx 2023-6-28 21:01:20 看全部
我看不错噢 谢谢楼主!知鸟论坛越来越好!
回复

使用道具 举报

发表于 2023-6-29 00:39:27 | 显示全部楼层
永远爱你冰塘 2023-6-29 00:39:27 看全部
其实我一直觉得楼主的品味不错!呵呵!知鸟论坛太棒了!
回复

使用道具 举报

发表于 2023-6-30 09:34:58 | 显示全部楼层
老橡树1 2023-6-30 09:34:58 看全部
楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
回复

使用道具 举报

发表于 2023-6-30 19:34:05 | 显示全部楼层
向往草原403 2023-6-30 19:34:05 看全部
论坛不能没有像楼主这样的人才啊!我会一直支持知鸟论坛
回复

使用道具 举报

发表于 2023-6-30 21:13:54 | 显示全部楼层
123456823 2023-6-30 21:13:54 看全部
我看不错噢 谢谢楼主!知鸟论坛越来越好!
回复

使用道具 举报

发表于 2023-7-1 00:57:58 | 显示全部楼层
麻辣鸡翅 2023-7-1 00:57:58 看全部
楼主,大恩不言谢了!知鸟论坛是最棒的!
回复

使用道具 举报

发表于 2023-7-3 09:02:09 | 显示全部楼层
十二音阶囤 2023-7-3 09:02:09 看全部
楼主发贴辛苦了,谢谢楼主分享!我觉得知鸟论坛是注册对了!
回复

使用道具 举报

发表于 2023-7-3 15:29:06 | 显示全部楼层
李志敏 2023-7-3 15:29:06 看全部
既然你诚信诚意的推荐了,那我就勉为其难的看看吧!知鸟论坛不走平凡路。
回复

使用道具 举报

发表于 2023-7-3 18:30:24 | 显示全部楼层
丁侦球 2023-7-3 18:30:24 看全部
楼主,大恩不言谢了!知鸟论坛是最棒的!
回复

使用道具 举报

  • 您可能感兴趣
点击右侧快捷回复 【请勿灌水】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则 返回列表

RSS订阅| SiteMap| 小黑屋| 知鸟论坛
联系邮箱E-mail:zniao@foxmail.com
快速回复 返回顶部 返回列表