C#学习笔记 -- 结构

1、什么是结构

结构是开发者定义的数据类型, 与类非常相似, 他们有数据成员和函数成员, 虽然与类很相似, 但是有区别

  • 类是引用类型, 而结构是值类型

  • 结构是隐式密封的, 他们不能派生出其他类

struct StructName
{
    Member
}
例子
struct Point1101
{
    public int X;
    public int Y;
}
static void Main(string[] args)
{
    //1101
    {
        Point1101 first;
        first.X = 10; first.Y = 10;
        Point1101 second;
        second.X = 30; second.Y = 20;
        Point1101 third;
        third.X = 30; third.Y = 30;
​
        Console.WriteLine($"点1: {first.X}, {first.Y}");
        Console.WriteLine($"点2: {second.X}, {second.Y}");
        Console.WriteLine($"点3: {third.X}, {third.Y}"); 
    }
}

2、结构是值类型

所有值类型引用, 结构类型变量含有自己的数据, 因此

  • 结构类型的变量不能为null

  • 两个结构变量不能引用同一个对象

  • 结构的字段值只存在与栈中

class CSimple
{
    public int X;
    public int Y;
}
struct Simple
{
    public int X;
    public int Y;
}
class Program
{
    static void Main(string[] args)
    {
        CSimple cs = new CSimple();
        Simple ss = new Simple();
    }
}

3、对结构赋值

把一个结构赋值给另一个结构, 就是将一个结构的值复制给另一个结构

  • 在类赋值之后, cs2和cs1执行堆中同一个对象,

  • 但是结构赋值之后, ss2的成员值和ss1的相同

class CSimple
{
    public int X;
    public int Y;
}
struct Simple
{
    public int X;
    public int Y;
}
static void Main(string[] args)
{
    CSimple cs1 = new CSimple();
    Simple ss1 = new Simple();
    CSimple cs2 = null;
    Simple ss2 = new Simple();
​
    cs1.X = ss1.X = 5;
    cs1.Y = ss1.Y = 10;
​
    cs2 = cs1;
    ss2 = ss1;
}

4、构造函数和析构函数

结构可以有实例构造函数和静态构造函数, 但是不能有析构函数

(1)实例构造函数

  • 语言隐式的为每个结构提供一个无参数的构造函数

  • 这个构造函数把结构的每个成员设置为该类型的默认值

    • 值成员设置成他们的默认值

    • 引用成员设置为null

  • 对于每个结构, 都存在预定义的无参构造器, 并且不能删除或重定义,

  • 但是可以创建另外的构造函数, 只要他们有参数, 与类是不同的, 对于类, 编译器只在没有声明其他构造函数时提供隐式的无参构造

  • 调用构造器, 结构也需要使用new运算符, 即时不从堆中分配内存

    struct Simple
    {
        public int X;
        public int Y;
    ​
        public Simple(int x, int y)
        {
            X = x;
            Y = y;
        }
    }
    Simple simple = new Simple(5, 10);
  • 也可不用new, 限制如下

    • 显式设置数据成员之后, 才能使用他们的值

    • 堆所有数据成员赋值之后, 才能调用结构的函数成员

struct Simple
{
    public int X;
    public int Y;
}
static void Mian(string[] args)
{
    Simple s1;
    Simple s2;
    Console.WriteLine($"{s1.X}, {s1.Y}"); //编译错误
    s2.X = 5;
    s2.Y = 10;
    Console.WriteLine($"{s1.X}, {s1.Y}"); //没问题
    Console.WriteLine($"{s2.X}, {s2.Y}"); //没问题
}

(2)静态构造函数

与类相似, 结构的静态构造函数创建并初始化静态数据成员, 不能引用实例成员, 结构的静态构造器遵从与类的静态构造器一样的规则, 但允许有不带参数的静态构造器

以下两种行为, 任意一种发生之前, 将会调用静态构造函数

  • 调用显示声明的构造函数

  • 引用结构的静态成员

(3)小结

类型 描述
无参实例构造 不能在程序中声明. 系统为所有结构提供一个隐式的构造函数, 不能被程序删除或重定义
有参实例构造 可以在程序中声明
静态构造函数 可以在程序中声明
析构函数 不允许声明

5、属性和字段初始化语句

  • 结构体声明中, 不允许使用实例属性和字段初始化语句

  • 但是结构体的静态属性和静态字段都可以声明结构体时进行初始化, 即使结构体本身不是静态的

struct Simple
{
    public int X = 0;  //编译错误
    public int Y = 19; //编译错误
​
    public int MyProp { set; get; } = 5; //编译错误
}

6、结构是密封的

  • 结构总是隐式密封, 不能派生其他结构

  • 由于不支持继承, 个别类修饰符用在结构成员上没有意义, 因此不能在结构成员声明中使用

    • protected

    • protected internal

    • abstract

    • sealed

    • virtual

  • 结构本身派生自System.ValueTypeSystem.ValueType派生自object

  • 两个可以用于结构成员并与继承相关的关键字是newoverride, System.ValueType的成员同名成员可以使用他们

7、装箱和拆箱

将一个结构实例作为引用类型对象必须装修, 反之是拆箱

8、结构作为返回值和参数

  • 返回值

    • 当结构作为返回值时, 将创建他的副本并从函数成员返回

  • 值参数

    • 当结构被用作值参数时, 将创建实参结构的副本. 该副本用于方法的执行中

  • ref 和 out参数

    • 如果把一个结构用作ref或out参数, 传入方法的是该结构的一个引用, 这样就可以修改其数据成员

9、其他

  • 给结构进行分配的开销比创建类实例小, 所以使用结构替代类有时候可以提高性能, 但要注意拆箱、装箱的代价

  • 预定义简单类型, 尽管在doNet、C#中被视为原始类型, 但是实际上在doNET中都实为结构

  • 可以使用与声明分部类相同的方法声明分部结构

  • 结构和类一样, 都可以实现接口

posted on 2023-05-25 00:28  老菜农  阅读(26)  评论(0编辑  收藏  举报

导航