1.结构声明
struct
类型定义包含数据成员和函数成员的结构,这一点与类类型相似。
struct 结构名<类型参数> : 接口
{
//结构体
}
2.继承
所有结构类型只能隐式派生自 System.ValueType类,结构类型不能从其它类或结构类型继承,也不能作为类的基础类型,因为结构类型是隐式密封的。
3.构造函数
如果显式声明一个无参数构造函数,那创建对象调用无参数构造函数时将调用该显式声明的无参数构造函数。
如果未显式声明一个无参数构造函数,那结构类型会自动提供一个隐式无参数构造函数,行为如下:
- 如果结构类型有显式的实例有参数构造函数或无字段初始值设定项,隐式的无参数构造函数会生成结构类型的默认值。
- 如果结构类型没有显式的实例有参数构造函数和有字段初始值设定项,编译器会合成一个执行字段初始值设定项的
public
无参数构造函数。
default(T)
默认值表达式会忽略无论显式还是隐式的无参数构造函数和字段初始值设定项并生成结构类型的默认值。
备注:默认值是通过如下设置生成的值:将所有值类型的字段设置为其默认值(0 位模式),将所有引用类型的字段设置为 null
。
4.创建对象
结构的创建对象与类的创建对象相似。
5.结构与类的区别
类是引用类型。创建类的对象后,向其分配对象的变量仅保留对相应内存的引用。将对象引用分配给新变量后,新变量会引用原始对象。通过一个变量所做的更改将反映到另一个变量中,因为它们引用相同的数据。
结构是值类型。创建结构时,向其分配结构的变量保留结构的实际数据。 将结构分配给新变量时,会复制结构。 因此,新变量和原始变量包含相同数据的副本(共两个)。对一个副本所做的更改不会影响另一个副本。
一般来说,类用于对更复杂的行为建模。类通常存储计划在创建类对象后进行修改的数据。结构最适用于小型数据结构。结构通常存储不打算在创建结构后修改的数据。
6.分部(partial)结构
拆分一个结构的定义到两个或更多的文件中,每个文件包含类型或方法定义的一部分,编译应用程序时将把所有部分组合起来。
partial struct S1
{
void Struct_Test() { }
}
partial struct S1
{
void Struct_Test2() { }
}
//合并后
struct S1
{
void Struct_Test() { }
void Struct_Test2() { }
}
7.非破坏性变化(nondestructive mutation)
非破坏性变化(nondestructive mutation)引用的是函数式编程里面的概念,意思是当您想要更改一个对象的状态时,创建原数据的拷贝与修改从而合成新数据优于直接修改原数据。
with
表达式会创建新的对象,此新的对象是已存在对象的副本与修改的特定属性和字段合成的新对象。使用对象初始值设定项语法来指定要修改的成员及其新值。
对于引用类型成员,在复制操作数时仅复制对成员实例的引用。
public readonly struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; init; }
public double Y { get; init; }
public override string ToString() => $"({X}, {Y})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
8.readonly修饰符
如果将整个结构类型声明为 readonly
,则该结构类型是不可变类型。
所有字段声明都必须具有readonly
修饰符。
所有属性(包括自动实现的属性)都必须为只读属性,无需添加readonly
修饰符。
不过,可变的引用类型的数据成员仍可改变其自身的状态。例如,不能替换 List<T>
实例,但可以向其中添加新元素。
readonly struct 结构名
{
//结构体
}
如果不能将整个结构类型声明为 readonly
,因为结构类型是可变类型,可使用 readonly
修饰符标记不会修改结构状态的实例成员(方法、属性、索引器),不能将 readonly
修饰符应用于结构类型的静态成员。
//方法
public readonly double Sum()
{
return X + Y;
}
//属性
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
9.ref修饰符
ref
结构类型的实例在堆栈上分配,并且不能转义到托管堆。
在 .NET 中,ref
结构的示例分别是 System.Span<T> 和 System.ReadOnlySpan<T>。
//将整个结构类型声明为ref
ref struct 结构名
{
//结构体
}
ref结构有如下限制:
ref
结构不能是数组的元素类型。ref
结构不能是类或非ref
结构的字段的声明类型。ref
结构不能实现接口。ref
结构不能被装箱为 System.ValueType 或 System.Object。ref
结构不能是类型参数。ref
结构变量不能由lambda
表达式或本地函数捕获。ref
结构变量不能在async
方法中使用。 但是,可以在同步方法中使用ref
结构变量,例如,在返回 Task 或 Task<TResult> 的方法中。ref
结构变量不能在迭代器中使用。
10.readonly ref修饰符
若要将 ref
结构声明为 readonly
,请在类型声明中组合使用 readonly
修饰符和 ref
修饰符(readonly
修饰符必须位于 ref
修饰符之前)。
readonly span
所使用的内存仅限于单个堆栈帧,并且readonly span
使用的内存无法进行修改。
原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/csharp/csharplang/7873.html