重庆熊猫 Loading

C#教程 - 结构类型(Struct Type)

更新记录
转载请注明出处:https://www.cnblogs.com/cqpanda/p/16675933.html
2022年9月15日 发布。
2022年9月10日 从笔记迁移到博客。

结构类型(Struct Type)说明

提供类似类的一种逻辑结构,是一种用户自定义的值类型,可以包含数值和方法

结构是值类型,不可以赋值为null

结构传参按 值传递

结构自带默认无参构造函数并且不可以删除

结构禁止字段成员声明时初始化

自定义结构的构造函数必须初始化所有成员

结构没有析构函数,但可以自定义实现IDisponse

结构是sealed,不可以派生

结构也可以是泛型的

结构可以实现接口

结构也支持分部结构

结构继承自System.ValueType,而System.ValueType继承自System.Object

预定义基础类型在.NET库中本质上都是定义为结构类型

结构与类对比

相同:结构 和 类 都具有 数据 和 函数成员

区别:

Class是引用类型,Struct是值类型

结构是隐式密封的,不可以派生(隐式集成自System.Object和System.ValueType)

Struct使用自定义的构造函数后,系统自带的构造函数不会消失

struct不支持带参数的构造函数(parameterless constructor)、析构函数(finalizer)

​ 在声明结构的时候进行不可以对字段赋值

​ struct不支持属性初始化器(field initializers)

​ struct不支持虚成员或保护字段(virtual or protected members)

一般情况下,结构的实例消耗小,使用结构可以提高一些性能,但是装箱和拆箱的消耗也不低,需要权衡考虑

尽量少或者最好不要在结构中定义方法,只让结构保存数据成员,用于管理数据集

结构可以包含类可以包含的所有成员,但以下成员除外:

无参数的构造函数(A parameterless constructor)

字段初始化(Field initializers)

析构器(A finalizer)

虚成员或保护成员(Virtual or protected members)

声明结构类型

struct Panda
{
}

注意:结构中的字段不可以直接定义时初始化

image

注意:结构类型中的成员不可以使用以下修饰符:

protected、internal、virtual、abstract

实例:声明结构的错误示例

public struct Point
{
    int x = 1;        // Illegal: field initializer
    int y;
    public Point() { }           // Illegal: parameterless constructor
    public Point(int x) { this.x = x; }  // Illegal: must assign field y
}

只读 与 结构

说明

注意:除非必要,否则尽量不要将值类型定义为不可变

只读结构(Read-only Structs)

只读结构内部所有的字段都只能是只读的,可以防止字段被修改

注意:从C# 7.2可用

注意:从C# 8开始支持只读方法

实例:只读结构内的只读字段

readonly struct Point
{
    //只读字段成员
    public readonly int _X;
    public readonly int _Y;
    public Point(int x, int y)
    {
        this._X = x;
        this._Y = y;
    }
}

实例:结构内的只读方法

struct Point
{
    public int X;
    public int Y;
    public Point(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }

    //只读方法
    public readonly void ResetX()
    {
        Console.WriteLine("Panda666");
    }
}

实例:可以给结构体内的方法定义为readonly,这样该方法就不可以修改成员

struct Point
{
    public int X, Y;
    public readonly void ResetX() => X = 0; // Error!
}

注意:如果readonly函数调用非readonly函数,编译器将生成警告

只读属性成员

从C# 6.0开始支持结构内定义只读属性

实例:

public struct PandaStruct
{
    //只读属性成员
    public string Property1 { get; }
    public string Property2 { get; }

    public PandaStruct(string arg1, string arg2)
    {
        this.Property1 = arg1;
        this.Property2 = arg2;
    }
}

引用结构(Ref Structs)

使用ref关键字修饰struct后,struct只能分配在栈上

注意:从C# 7.2 开始可用

常见使用场景:

配合e Span 和 ReadOnlySpan structs使用

实例:ref struct分配到堆上,出现错误

ref struct Point { public int X, Y; }
class MyClass { Point P; } 
// Error: will not compile! 作为类的成员,将分配在堆上
var points = new Point [100];
// Error: will not compile! 作为数组的类型,数组分配在堆上

实例:可以用ref struct的地方和不可以用的地方

using System;
using System.Text.Json;

namespace ConsoleApp2
{
    /// <summary>
    /// 定义引用结构体
    /// </summary>
    public ref struct PandaStruct
    {
        public string Code{ get; set; }
        public string Title { get; set; }
    }

    public class PandaClass
    {
        //定义成员
        public PandaStruct E;  //error,不可以这样
    }

    class Program
    {
        static void Main(string[] args)
        {
            //这样是可以的
            PandaStruct pandaStruct = new PandaStruct();

            //wait
            Console.ReadKey();
        }
    }
}

结构赋值

结构是值类型,所以一般存储在栈上
image

结构与结构之间赋值是复制的内容,而类之间的赋值时复制的引用
image

构造函数与析构函数

结构可以有构造函数,但是不可以有析构函数

结构默认自带一个无参数的构造函数,并且该构造函数不可以删除和自定义

但可以自定义其他构造函数

结构的构造函数可以是静态的
image

实例化结构

实例化结构可以使用new或者不使用new

不使用new的话,需要把每个字段都赋值之后才可以使用其函数成员

using System;

namespace Test
{
    struct Panda
    {
        private int _x;
        private int _y;

        public Panda(int x, int y)
        {
            this._x = x;
            this._y = y;
        }
    }

    class Program
    {
        static void Main()
        {
            Panda s = new Panda(1, 2);

            Console.ReadKey();
        }
    }
}

实例:实例化结构默认值

struct PandaStruct { }
PandaStruct pandaStruct = default;

数据成员默认初始化的默认值

Unlike with instance fields

if no initialization for a static field is provided

the static field will automatically be assigned its default value (0, null, false, and so on)—the equivalent of default(T)

结构装箱和拆箱

装箱(boxing):将 值类型 包装为 引用类型

拆箱(unboxing):将 引用类型 中的数据转为 值类型

结构作为返回值和参数

作为返回值:返回的是结构实例的值副本

作为值参数:使用的是实参的值副本

ref和out参数:结构作为ref或out参数,传入的参数是结构实例的别名

泛型结构

struct Panda<T>
{
    public Panda(T code)
    {
        this.Code = code;
    }

    public T Code { get; set; }
}

结构最佳实践

除非结构在逻辑上表示单个值,占用16个字节或更少的存储空间

不可变且不经常装箱,否则请勿定义结构

posted @ 2022-09-15 08:01  重庆熊猫  阅读(582)  评论(0编辑  收藏  举报