关于c#:价值类型,不变性(好)&

Value Types, Immutability (Good) & Mutability (Evil) in .NET

本问题已经有最佳答案,请猛点这里访问。

我最近阅读了很多关于价值类型和参考类型及其差异的文献。这个问题围绕着值类型的可变性和不可变性的主题。

根据我读到的内容,似乎.NET中的值类型应该以不可变的方式写入;也就是说,一旦为它们分配了一个值,该类型在内存中的值就不会改变。只有类型的后续副本才能使用基于原始值的新值在内存中构造新实例。在.NET中,易变性似乎是邪恶的。

为了澄清对不变性的理解(为了我自己的理智和他人的理智),我在下面演示了这一点:

DateTimeTimeSpan是不可变结构的例子,因为一旦一个值被分配给一个实例,该实例的值就不能改变,这通过只读属性很明显:

1
2
3
DateTime dt = new DateTime();
DateTime newdt = dt.AddDays(2); // Okay, new value stored in newdt
newdt.Year = 1945; // Error, cannot write to readonly property

但是,当查看ar基元类型(如Int32DoubleChar时,不可变性可能会令人困惑,因为这些类型似乎是可变的,但我的直觉是,实际上,不可变性是通过clr透明地处理的;例如以下操作(我在一些非常基本的x86中评论过,相当于理解如何在基本类型中处理不变性)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int x = 0;

// xor eax, eax;     'clear register to 0
// push eax;         'push eax (0) onto the stack

x = 5;

// pop eax;          'pop stack (0) into eax
// mov eax, 5;       'eax = 5
// push eax;         'push eax (5) onto the stack

x++;

// pop eax;          'pop stack (5) into eax
// add eax, 1;       'eax = 5 + 1
// push eax;         'push eax (6) onto the stack

到目前为止一切都很好;微软似乎在实现其价值类型的不变性方面做得很好;但随后我们开始发现不好的苹果,并细分使易变性看起来正常的细微差别,诱使开发人员产生一种错误的安全感!

我说的是系统中的点、大小、矩形(以及其他一些)。

突然间,我们被赋予了根据一个值的属性改变它的类型的能力,我有了一个理论来解释为什么这是可能的;例如下面的代码

1
2
3
4
5
6
7
8
Point p = new Point();
p.X = 100;
p.Y = 200;

// Immutability (had it been implemented here) might infer the following usage

Point p = new Point(100, 200);
Point p2 = p.AddXY(200, 300);

然而,如前所述,我有一个理论解释为什么这些结构是可变的:

  • 微软只是想让这些结构更容易使用。
  • 它们与本地GDI/GDI+调用互操作,因此它们的行为是围绕它们的本地C/C++对应来设计的。
  • 最后我的问题是:

  • 我是否完全覆盖并理解了不可变性和可变性?
  • 开发人员是否应该将构建不可变结构作为规则?
  • 什么时候可以构建可变结构?

  • 可变性问题不是值与引用类型的问题。两者都有例子。以System.String为例说明不可变类,以System.Drawing.Point为例说明可变结构。

    可变与不可变是基于类型用法的设计决策。它是引用类型还是值类型是另一个不依赖于前者的设计决策。


    六羟甲基三聚氰胺六甲醚。。。这可能很快就要结束了,但我的观点是。

  • 是的,似乎你理解了不可变和不可变。
  • 应该是一个重要的词。开发人员应该意识到这些差异,非常关心它们的交易,并且有常识地问自己:我需要从这个特定的结构中得到什么。
  • 可接受的?我猜你什么时候需要它。你什么时候需要一个是一个完全不同的问题。
  • 通常使用结构来保存一些属性或基元类型。有一些关于您应该和不应该在结构中拥有什么的文章,以便它们在堆或堆栈上结束,但这超出了这里的范围。如果您有一个令人信服的理由使用可变结构,并将其记录下来,以便下一个开发人员知道原因,那就没问题了。如果相反,你不在乎,文档也不在你的列表中,那么,什么是可接受的或者不可接受的并不重要。