.NET中的值类型,不变性(好)和可变性(邪恶)

ser*_*0ne 5 .net c# struct mutable immutability

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

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

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

DateTime并且TimeSpan不可变结构的示例,因为一旦将值赋给实例,该实例值就不会改变,这通过只读属性很明显:

DateTime dt = new DateTime();
DateTime newdt = dt.AddDays(2); // Okay, new value stored in newdt
newdt.Year = 1945; // Error, cannot write to readonly property
Run Code Online (Sandbox Code Playgroud)

然而,当看到原始类型时,不变性可能会令人困惑Int32,Double或者Char,因为类型似乎是可变的,但我的直觉是实际上,通过CLR透明地处理不变性; 以下是一些操作(我在一些非常基本的x86中进行了评论,以了解如何根据原始类型处理不变性)

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
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利; 微软似乎在将不可变性实现到其价值类型方面做得很好; 但后来我们开始发现坏苹果,并且让可变性看起来不错的细微差别让开发人员陷入虚假的安全感!

我在谈论System.Drawing命名空间中的Point,Size,Rectangle(以及其他几个).

突然间,我们被赋予了通过它的属性来改变值类型的能力,并且我有一个关于为什么这是可能的理论; 以下面的代码为例

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);
Run Code Online (Sandbox Code Playgroud)

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

  1. 微软只是希望能够更轻松地使用这些结构.
  2. 它们可与本机GDI/GDI +调用互操作,因此它们的行为是围绕其本机C/C++对应物设计的.

最后我的问题:

  1. 我是否已完全涵盖并理解不变性和可变性?
  2. 开发人员是否应该通常建立不可变结构?
  3. 何时可以构建可变结构?

nvo*_*igt 6

可变性问题不是价值与参考类型之一.两者都有例子.以System.String不可变类为例,以及作为System.Drawing.Point可变结构示例的示例.

Mutable与immutable是基于类型用法的设计决策.无论是引用还是值类型,都是另一个不依赖于前者的设计决策.