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
{
}
注意:结构中的字段不可以直接定义时初始化
注意:结构类型中的成员不可以使用以下修饰符:
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
实例: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个字节或更少的存储空间
不可变且不经常装箱,否则请勿定义结构
本文来自博客园,作者:重庆熊猫,转载请注明原文链接:https://www.cnblogs.com/cqpanda/p/16675933.html