一文搞懂C#中的赋值、深复制、浅复制

一、文字含义

先引入一个观念,赋值和深复制、浅复制并不是一样的,含义是不一样的。

本文所说的主要是针对“ 引用类型 ”本文以 “类 ”为例加以说明。一般的系统定义的值类型(int、double、float等等)此处不做考虑。

1、赋值。指的是 “ 等号= ”。它相当于是给引用对象起一个别名。

2、浅度复制和深度复制。指的是类实现 ICloneable接口,重写该接口的唯一方法。注意:不管是深度复制还是浅度复制,都是通过ICloneable接口去实现的。

二、实例代码

1、赋值

此处定义了一个父亲类Parent,他有三个属性 年龄Age,身高Height,孩子信息child,但是孩子信息又包含三个信息,即姓名Name,年龄Age,体重Weight。对于父类Parent而言,Age、Height是“ 值类型 ”,而成员child是“ 引用类型 ”。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 赋值_深度复制_浅度复制
{
    class Program
    {
        static void Main(string[] args)
        {
            Parent parent_01 = new Parent();
            parent_01.Age = 48;
            parent_01.Height = 173;
            parent_01.child = new Children("菲菲", 25, 55.55);
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
            Parent parent_02 = parent_01;
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
            Console.WriteLine("===========================================");
            parent_02.Age = 60;
            parent_02.Height = 189;
            parent_02.child.Age = 35;
            parent_02.child.Name = "宝宝";
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
        }
    }
    class Parent
    {
        private int age;
        private double height;
        public Children child;

        public Parent()
        {

        }

        public int Age { get => age; set => age = value; }
        public double Height { get => height; set => height = value; }
    }
    class Children
    {
        private string name;
        private int age;
        private double weight;
        public Children(string name,int age,double weight)
        {
            this.name = name;
            this.age = age;
            this.weight = weight;
        }

        public string Name { get => name; set => name = value; }
        public int Age { get => age; set => age = value; }
        public double Weight { get => weight; set => weight = value; }
    }
}

运行结果如下:

年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
===========================================
年龄:60 身高:189 孩子的信息为:宝宝 35 55.55
年龄:60 身高:189 孩子的信息为:宝宝 35 55.55
请按任意键继续. . .

===================================================================

总结:parent_01和parent_02完全是共用的,不管是引用类型成员,还是值类型成员,都是共用的,parent_02任何成员改变,parent_01都会跟着改变。

2、浅复制

给父类Parent实现ICloneable接口,重写Clone方法,注意,默认的MemberWiseClone()就是系统实现的“ 浅度复制 ”。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 浅复制
{
    class Program
    {
        static void Main(string[] args)
        {
            Parent parent_01 = new Parent();
            parent_01.Age = 48;
            parent_01.Height = 173;
            parent_01.child = new Children("菲菲", 25, 55.55);
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
            Parent parent_02 = parent_01.Clone() as Parent;
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
            Console.WriteLine("===========================================");
            parent_02.Age = 60;
            parent_02.Height = 189;
            parent_02.child.Age = 35;
            parent_02.child.Name = "宝宝";
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
        }
    }
    class Parent:ICloneable
    {
        private int age;
        private double height;
        public Children child;

        public Parent()
        {

        }

        public int Age { get => age; set => age = value; }
        public double Height { get => height; set => height = value; }
        public object Clone()
        {
            return this.MemberwiseClone();  //浅复制
        }
    }
    class Children
    {
        private string name;
        private int age;
        private double weight;
        public Children(string name, int age, double weight)
        {
            this.name = name;
            this.age = age;
            this.weight = weight;
        }

        public string Name { get => name; set => name = value; }
        public int Age { get => age; set => age = value; }
        public double Weight { get => weight; set => weight = value; }
    }
}

运行结果为:

年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
===========================================
年龄:48 身高:173 孩子的信息为:宝宝 35 55.55
年龄:60 身高:189 孩子的信息为:宝宝 35 55.55
请按任意键继续. . .

总结:从上可以看出,对于父亲类Parent的值类型成员,parent_01和parent_02是不共用的,parent_02改变,parent_01独立的,并不会改变;但是对于引用类型成员child,parent_01和parent_02是共用的,parent_02改变,parent_01也会跟着改变。

3、深度复制

深度复制的实现和浅度复制类似,只不过是重载的Clone方法实现不一样,具体可参见代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 深复制
{
    class Program
    {
        static void Main(string[] args)
        {
            Parent parent_01 = new Parent();
            parent_01.Age = 48;
            parent_01.Height = 173;
            parent_01.child = new Children("菲菲", 25, 55.55);
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
            Parent parent_02 = parent_01.Clone() as Parent;
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
            Console.WriteLine("===========================================");
            parent_02.Age = 60;
            parent_02.Height = 189;
            parent_02.child.Age = 35;
            parent_02.child.Name = "宝宝";
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
            Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
        }
    }
    class Parent : ICloneable
    {
        private int age;
        private double height;
        public Children child;

        public Parent()
        {

        }

        public int Age { get => age; set => age = value; }
        public double Height { get => height; set => height = value; }
        public object Clone()
        {
            Parent newparent = new Parent();
            newparent.Age = 48;newparent.Height = 173;
            newparent.child = new Children("菲菲", 25, 55.55);
            Object newParent = newparent;
            return newParent;  //深复制
        }
    }
    class Children
    {
        private string name;
        private int age;
        private double weight;
        public Children(string name, int age, double weight)
        {
            this.name = name;
            this.age = age;
            this.weight = weight;
        }

        public string Name { get => name; set => name = value; }
        public int Age { get => age; set => age = value; }
        public double Weight { get => weight; set => weight = value; }
    }
}

运行结果为:

年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
===========================================
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
年龄:60 身高:189 孩子的信息为:宝宝 35 55.55
请按任意键继续. . .

总结:从上可以看出,对于父亲类Parent的所有成员,parent_01和parent_02是完全不共用的,parent_02改变,不管是改变父亲类Parent的值类型成员,还是应用类型成员,parent_01都是独立的,并不会改变。

三、总结

1、赋值。赋值和深度复制,浅度复制完全是不同的概念,并没有什么关系,很多文章说赋值对于值类型是深度复制,对于引用类型是浅度复制,这种说法是不正确的,它的本质是在线程栈上产生一样的副本。

2、浅度复制。值类型成员独立,但是引用类型成员共享。

3、深度复制。值类型成员和引用类型成员都是独立的,即完完全全的一个全新的副本,称之为深度复制。

有兴趣的可以参考python的深度复制和浅度复制,有类似的地方。

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
CAN(Controller Area Network,控制器局域网)总线协议是一种广泛应用于工业自动化、汽车电子等领域的串行通讯协议。其帧格式如下: <img src="https://img-blog.csdnimg.cn/20200925125252655.png" width="400"> CAN总线协议的帧分为标准帧和扩展帧两种,其标准帧包含11位标识符,扩展帧包含29位标识符。在CAN总线上,所有节点都可以同时发送和接收数据,因此需要在帧包含发送方和接收方的信息。 帧格式的具体解释如下: 1. 帧起始符(SOF):一个固定的位模式,表示帧的起始。 2. 报文控制(CTRL):包含几个控制位,如IDE、RTR等。其IDE表示标识符的类型,0表示标准帧,1表示扩展帧;RTR表示远程请求帧,0表示数据帧,1表示远程请求帧。 3. 标识符(ID):11位或29位的标识符,用于区分不同的CAN消息。 4. 控制域(CTL):包含几个控制位,如DLC、EDL等。其DLC表示数据长度,即数据域的字节数;EDL表示数据长度是否扩展,0表示标准数据帧,1表示扩展数据帧。 5. 数据域(DATA):0~8字节的数据。 6. CRC:用于校验数据是否正确。 7. 确认位(ACK):由接收方发送的确认信息,表示数据是否正确接收。 8. 结束符(EOF):一个固定的位模式,表示帧的结束。 以上就是CAN总线协议的帧格式。在实际应用,节点之间通过CAN总线进行数据交换,通过解析帧的各个字段,可以判断消息的发送方、接收方、数据内容等信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值