02011101 结构

02011101 结构

1. 什么是结构

  • 结构是程序员定义的数据类型,与类非常类似,结构也有数据成员和函数成员。
  • 结构虽然与类类似,但是结构对比类有许多重要的区别如下。
    • 类是引用类型,结构是值类型。
    • 结构是隐式封闭的,这意味着不能从它派生其它结构。
// 声明结构的语法
struct StructName
{
	...
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using System; 

namespace Demo01
{
    struct MyStruct
    {
        public int X;
        public int Y;
    }
    class Program
    {
        static void Main()
        {
            MyStruct myStruct01;
            MyStruct myStruct02;

            myStruct01.X = 10;
            myStruct01.Y = 11;
            myStruct02.X = 20;
            myStruct02.Y = 21;
            Console.WriteLine($"{myStruct01.X}, {myStruct01.Y}");
            Console.WriteLine($"{myStruct02.X}, {myStruct02.Y}");

            Console.ReadLine();
        }
    }
}

控制台输出:
10, 11
20, 21

2. 结构是值类型

  • 和所有值类型一样,结构类型的变了含有自己的数据,因此:
    • 结构类型的变量不能为null。
    • 两个结构变量不能引用同一对象。(这句话没有理解,后续补充)
  • 结构在内存中的分布。
图片链接丢失
类的内存安排与结构的内存安排
class CSimple
{
    public int X;
    public int Y;
}

struct Simple
{
    public int X;
    public int Y;
}

class Program
{
    static void Main()
    {
        CSimple cs = new CSimple();
        Simple ss = new Simple();
        ...
    }
}

3. 对结构赋值

  • 把一个结构赋值给另一个结构,就是将一个结构的值复制给另一个结构。注意,这和复制类变量不同,复制类变量时只复制引用。
图片链接丢失
类的内存安排与结构的内存安排
class CSimple
{
    public int X;
    public int Y;
}

struct Simple
{
    public int X;
    public int Y;
}

class Program
{
    static void Main()
    {
        CSimple cs1 = new CSimple();
        CSimple cs2 = null;
        Simple ss1 = new Simple();
        Simple ss2 = new Simple();
        cs1.X = ss1.X = 5; // 将5赋值给ss1.X和cs1.X;
        cs2.Y = ss2.Y = 10; // 将10赋值给ss2.Y和cs2.Y
        
        cs2 = cs1; // 赋值类实例
        ss2 = ss1; // 赋值结构实例
    }
}

4. 构造函数和析构函数

  • 结构可以有实例构造函数和静态构造函数,但是不能有析构函数。
4.1 实例构造函数
  • C#隐式的为每个结构提供一个无参的构造函数。这个构造函数把结构的每个成员设置为该类型的默认值。
    • 值成员设置成它们的默认值,引用成员设置成null。
  • 对于每个结构,都存在预定义的无参构造函数,而且这个无参的构造函数不能删除或重定义。
    • 注意,这里和类不同。对于类,只有在没有声明其它构造函数时提供隐式的构造函数。
4.2 不使用new运算符创建结构的实例
  • 不适用new创建结构的实例有如下限制。
    • 在显式设置数据成员之后,才能使用它们的值。
    • 在对所有数据成员赋值之后,才能调用结构的函数成员。
using System; 

namespace Demo01
{
    struct MyStruct
    {
        public int X;
        public int Y;

        public MyStruct(int a, int b)
        {
            X = a;
            Y = b;
        }
    }
    class Program
    {
        static void Main()
        {
            MyStruct mys01 = new MyStruct(); // 通过new调用无参的构造函数,此时X和Y为默认值。
            MyStruct mys02 = new MyStruct(10, 20); // 通过new调用有参的构造函数,此时X=10,Y=20。

            Console.WriteLine($"{mys01.X},{mys01.Y}");
            Console.WriteLine($"{mys02.X},{mys02.Y}");

            MyStruct mys03; // @1 不通过new创建结构对象
            mys03.X = 100; // @2
            mys03.Y = 200; // @3
            Console.WriteLine($"{mys03.X},{mys03.Y}"); // @4

            Console.ReadLine();
        }
    }
}

控制台输出:
0,0
10,20
100,200

说明:在@1处不适用new运算符创建结构对象,必须在@2和@3处将所有数据成员赋值,然后才能在@4处使用结构对象。
4.3 属性和字段初始化语句
struct MyStruct
{
    public int x = 0; // 编译错误
    public int p1{get; set;} // 编译错误
    static int z = 30; // 正确
    static int p2(get; set;) = 5; // 正确
}

说明:
1. 在声明结构体时,不允许使用实例属性和字段初始化语句。
2. 在声明结构体时,结构体的静态属性和静态字段都可以在声明结构体时进行初始化。
4.4 结构是密封的
  • 结构是隐式密封的,因此他不能派生其它结构。由于结构不支持继承,因此部分类的成员修饰符在结构成员上没有意义,因此不能在结构上使用,不能用于结构的修饰符如下:
    • protected
    • protected internal
    • abstract
    • sealed
    • virtual
4.5 结构作为返回值和参数
  • 当结构用作返回值时,将创建它的副本并从函数成员返回。
  • 当结构作为值参数时,将创建实参结构的副本。该副本用于方法的执行中。
  • ref和out参数,如果把一个结构用作ref或out参数,传入方法的是结构的一个引用,这样就可以修改其数据成员。
4.6 关于结构的更多内容
  • 对结构分配的内存开销比类小,所以使用结构代替类有时可以提高性能,但是要注意装箱和拆箱的高昂代价。
  • 预定义简单类型(int,short,long,等等),尽管.NET和C#中被视为原始类型,但是它们实际上再.NET中都实现为结构。
  • 可以使用与声明分部类的方法声明分布结构。
  • 结构和类一样,可以实现接口。

结尾

书籍:C#图解教程

著:【美】丹尼尔 · 索利斯;卡尔 · 施罗坦博尔

译:窦衍森;姚琪琳

ISBN:978-7-115-51918-4

版次:第5版

发行:人民邮电出版社

※敬请购买正版书籍,侵删请联系85863947@qq.com※

※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※

posted @ 2025-08-12 23:38  qinway  阅读(6)  评论(0)    收藏  举报