如果您要使用结构体,最佳实践是使它们不可变。
将所有字段设置为只读是一种很好的方式,可以帮助 (1) 说明结构体是不可变的,以及 (2) 防止意外更改。
但是,有一个问题,我正巧打算在下周写博客讨论它。那就是:在结构体字段上使用readonly是一个谎言。人们期望一个只读字段不能改变,但它实际上是可以改变的。在结构体字段上标记“readonly”,就像支票账户没钱写支票一样。 结构体不拥有它的存储空间,而正是这个存储空间可以发生变化。
例如,让我们看看您的结构体:
public struct Pair
{
public readonly int x;
public readonly int y;
public Pair(int x, int y)
{
this.x = x;
this.y = y;
}
public void M(ref Pair p)
{
int oldX = x;
int oldY = y;
Debug.Assert(x == oldX);
Debug.Assert(y == oldY);
}
}
“在这里发生的某些事情”可能会导致调试断言被违反吗?当然。
public void M(ref Pair p)
{
int oldX = this.x;
int oldY = this.y;
p = new Pair(0, 0);
Debug.Assert(this.x == oldX);
Debug.Assert(this.y == oldY);
}
...
Pair myPair = new Pair(10, 20);
myPair.M(ref myPair);
现在会发生什么?断言被违反了!"this"和"p"引用同一个存储位置。该存储位置被改变,所以"this"的内容也被改变了,因为它们是同一件事。结构体不能强制 x 和 y 的只读性,因为结构体不拥有存储;存储是一个局部变量,可以自由地进行突变。
您不能 依赖 于这样一个不变式:结构体中的只读字段永远不会改变;您唯一可以依赖的是您无法编写直接更改它的代码。但是通过像这样的一些偷偷摸摸的工作,您可以间接地随意更改它。
另请参见乔·达菲(Joe Duffy)在此问题上的卓越博客文章:
http://joeduffyblog.com/2010/07/01/when-is-a-readonly-field-not-readonly/
readonly
属性/成员只能在构造函数内(最晚)设置。它们不能使用属性初始化语法进行设置。 - user166390readonly
只影响赋值运算符。它的语义不像 C++ 的const
关键字那样强。 - Etienne de Martel