更新记录
转载请注明出处:https://www.cnblogs.com/cqpanda/p/16675933.html
2022年9月15日 发布。
2022年9月10日 从笔记迁移到博客。
提供类似类的一种逻辑结构,是一种用户自定义的值类型,可以包含数值和方法
结构是值类型,不可以赋值为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 { }
注意:结构中的字段不可以直接定义时初始化
注意:结构类型中的成员不可以使用以下修饰符:
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 }
注意:除非必要,否则尽量不要将值类型定义为不可变
只读结构内部所有的字段都只能是只读的,可以防止字段被修改
注意:从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关键字修饰struct后,struct只能分配在栈上
注意:从C# 7.2 开始可用
常见使用场景:
配合e Span
实例: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(); } } }
结构是值类型,所以一般存储在栈上
结构与结构之间赋值是复制的内容,而类之间的赋值时复制的引用
结构可以有构造函数,但是不可以有析构函数
结构默认自带一个无参数的构造函数,并且该构造函数不可以删除和自定义
但可以自定义其他构造函数
结构的构造函数可以是静态的
实例化结构可以使用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个字节或更少的存储空间
不可变且不经常装箱,否则请勿定义结构