C#结构体(Struct)小结(一切尽有,建议收藏!!!)

前言:通过这篇文章让你清晰的搞明白在C#中什么是结构体以及结构体与类之间的区别,推荐刚入门的小白白收藏嗷!!!

目录:

    • 一、结构体的概念
    • 二、结构体的特征
    • 三、结构体的作用
    • 四、结构体的声明
    • 五、结构体的用法
    • 六、结构体与类的区别
      • 1.表格告诉你
      • 2.在赋值时
      • 3.实例构造函数
      • 4.静态构造函数
    • 七、结构体和类的使用场景

一、结构体的概念

在C#中,结构体是值类型的数据结构,它使得一个单一变量可以存储各种数据类型的相关数据。结构体用来代表一个记录。结构体是用struct关键字声明的。


二、结构体的特征

  1. 结构体可以有方法、域、属性、索引器、操作方法、事件。
  2. 结构体可以定义构造函数(实例和静态构造函数),但是不能构造析构函数。(虽然说可以定义构造函数,但是不能定义无参构造函数,因为结构体的无参构造函数是自动定义的且不能被改变,默认的无参构造函数会一直存在,默认的无参构造函数不会因为定义了有参构造函数就消失,这里说的都是实例构造函数)
  3. 结构体不能继承其他结构体或者其他类。
  4. 结构体不能用于作为其他结构体或者类的基类。
  5. 结构体类型总是隐式密封的,不能指定为密封的和抽象的,因此在定义结构时不能使用sealed和abstract关键字。
  6. 结构体成员不能被指定为抽象的、虚拟的、或者保护的对象,因此结构体的成员不能使用如下访问修饰符:abstract、virtual和protected
  7. 结构体的函数成员不能声明为abstract和virtual,但是可以使用override关键字,用以覆写它的基类System.ValueType中的方法。
  8. 结构体可以实现一个或多个接口。
  9. 使用New运算符创建结构体对象时,将创建该结构体对象,并且调用适当的构造函数。
  10. 如果不使用New运算符创建结构体对象,那么在初始化所有字段前,字段将保持未赋值状态,且对象不可用。

三、结构体的作用

  1. 结构是值类型,在分配内存的时候,速度非常快,因为它们将内联或者保存到栈中,在结构超出作用域被删除时速度也很快
  2. 结构体可以把功能相同的数据组织起来,存在一起,用是时候方便,而且在调用函数时,若传递参数较多,传一个结构体相对而言简单一些,很多系统自带的函数必须用结构体。
  3. 结构体在使用时可以和枚举一起使用。C#枚举总结

四、结构体的声明

定义结构体的语法如下:

1
2
3
4
[访问修饰符] struct 结构体的名字
{
    结构体成员
}

1.访问修饰符:
因为结构体类型总是隐式密封的,不能指定为密封的和抽象的,因此在定义结构时不能使用sealed和abstract关键字。

2.结构体成员:

  • 结构体成员不能被指定为抽象的、虚拟的、或者保护的对象,因此结构体的成员不能使用如下访问修饰符:abstract、virtual和protected
  • 结构体的函数成员不能声明为abstract和virtual,但是可以使用override关键字,用以覆写它的基类System.ValueType中的方法。

五、结构体的用法

如果不使用New运算符创建结构体对象,那么在初始化所有字段前,字段将保持未赋值状态,且对象不可用。
在这里插入图片描述
实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        public struct StudentStruct
        {
            public string Name { get; set; }
            public string Sex { get; set; }
            public int Num { get; set; }
            public int Code { get; set; }
            public StudentStruct(string name, string sex, int num, int code)
        {
            //这是有参构造函数
            this.Name = name;
            this.Sex = sex;
            this.Num = num;
            this.Code = code;
        }
        public void getvalues(string name,string sex,int num,int code)
        {
            //这是getvalues方法
            this.Name = name;
            this.Sex = sex;
            this.Num = num;
            this.Code = code;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            StudentStruct stu1=new StudentStruct("小明","男",20180705,88);
            //stu1.getvalues("小明","男",20180705,88);//注意:这里调用getvalues方法和有参构造函数都行
            Console.WriteLine($"姓名:{stu1.Name}");
            Console.WriteLine($"性别:{stu1.Sex}");
            Console.WriteLine($"学号:{stu1.Num}");
            Console.WriteLine($"成绩:{stu1.Code}");
            Console.ReadLine();
        }
    }

结果:
在这里插入图片描述


六、结构体与类的区别

1.表格告诉你

先用一个表格来简略看看结构体与类有什么区别:

条件 结构体
数据类型 值类型 引用类型
是否必须使用new运算符实例化
是否可声明无参数的构造函数
数据成员可不可以在声明的同时初始化 声明为const或static可以,数据成员不可以 可以
直接派生自什么类型 System.ValueType System.Object
有无析构函数
可不可以从类派生 不可以 可以
可不可以实现接口 可以 可以
实例化时在栈还是在堆分配内存 堆,栈中保存引用
该类型的变量可不可以被赋值为null 不可以 可以
可不可以定义私有的无参构造函数 不可以 可以
是否总有一个默认的无参构造函数

注意:这里解释一下表中最后一个条件,因为在类中手动定义了无参构造函数,这时就没有默认的无参构造函数了,所以说不是总有一个默认的无参构造函数。

无论结构体使用默认的无参构造函数,还是使用用户定义的有参构造函数进行初始化,都会初始化结构体的数据成员。不过默认的无参构造函数的会将数值类型初始化为默认值,引用类型初始化为null;而用户自定义的有参构造函数会对每个成员进行初始化。因此结构类型的数据成员不允许在声明时显式初始化。

下面我们具体分析一下结构体与类的区别:

2.在赋值时

如果从结构中创建一个对象,并将该对象赋给某个变量,则该变量包含结构的全部值。赋值类型为结构体的变量时,将同时复制该结构体所持有的所有数据。由于结构体不是引用类型,因此结构体类型的变量不能被赋予null值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    //结构体
    struct StudentStruct
    {
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Num { get; set; }
        public int Code { get; set; }
    }
    //类
    class StudentClass
    {
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Num { get; set; }
        public int Code { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //结构体中
            StudentStruct stu1 = new StudentStruct();
            StudentStruct stu2 = new StudentStruct();
            stu1.Name = "张三";
            stu1.Sex = "男";
            stu1.Num = 20180703;
            stu1.Code = 90;
            stu2 = stu1;//将stu1的值赋给stu2,由于结构体是值类型,因此赋值等于将stu1全部值全部复制到stu2的栈空间
            stu2.Name = "王麻子";//修改stu2的值看是否会影响stu1的值
            Console.WriteLine(stu1.Name);//输出张三,没影响,这里是因为stu1把所有数据全部复制给stu2,这时stu1和stu2两个对象互不干扰,所以说修改stu2的属性值不会影响stu1对应的属性值    
           
            //类中
            StudentClass stu3 = new StudentClass();
            StudentClass stu4 = new StudentClass();
            stu3.Name = "张三";
            stu3.Sex = "男";
            stu3.Num = 20180703;
            stu3.Code = 90;
            stu4 = stu3;//将stu3的值赋给stu4,由于类是引用类型,因此赋值等于两个对象指向的是同一个地址(堆空间)
            stu4.Name = "王麻子";//修改stu4的值看是否会影响stu3的值
            Console.WriteLine(stu3.Name);//输出王麻子,有影响,这里是因为stu3只是把指针位置复制给了stu4,它们两个指向同一个地址,这时stu3和stu4两个对象紧密相连,所以说不论修改哪个对象的属性值另一个对象对应的属性值也会改变

            Console.ReadLine();
        }
    }

总结:将一个结构变量赋值给另一个结构变量,就是把数据从一个结构复制到另一个结构。而类则不同,在类的变量之间,复制的是引用,而不是类数据。

3.实例构造函数

类的实例构造函数直通车:类的实例构造函数

相同点:结构体和类都有一个默认的无参构造函数。

不同点:在结构体中,默认的无参构造函数不允许删除和重定义,并且这个默认的无参构造函数会一直存在,并不会因为定义了其他带参数的构造函数就消失,这一点和类不同。

注意:结构体在使用有参构造函数时,当定义带参数的构造函数时,一定要完成结构体所有字段的初始化,如果没有完成所有字段的初始化,编译时会发生错误-。

4.静态构造函数

类的静态构造函数直通车:类的静态构造函数

相同点:结构类型也可以有静态构造函数,静态构造函数用于初始化静态数据成员。

不同点:结构和类的静态构造函数的触发规则不同,类的静态构造函数是在创建第一个实例或引用任何静态成员之前自动调用的,而结构的静态构造函数在以下情况调用:

  1. 使用显式声明的静态构造函数进行实例化
  2. 调用结构的方法或访问结构的静态数据成员(无论是读取还是赋值,访问实例数据成员不会触发,CLR自动调用静态的构造函数)。

七、结构体和类的使用场景

  1. 当堆栈的空间很有限,且有大量的逻辑对象时,创建类要比创建结构好一些。
  2. 对于点、矩形和颜色这样的轻量对象,假如要声明一个含有许多个颜色对象的数组,则CLR需要为每个对象分配内存,在这种情况下,使用结构的成本较低。
  3. 在表现抽象和多级别的对象层次时,类是最好的选择,因为结构不支持继承。
  4. 大多数情况下,目标类型只是含有一些数据,或者以数据为主,结构体则是最佳选择。

看完这篇文章,你是否搞明白了C#中的结构体以及结构体与类的区别呢?明白了能否点个赞再走,有问题评论区见!!!