【问题标题】:Value Types, Immutability (Good) & Mutability (Evil) in .NET [duplicate].NET 中的值类型、不变性(良好)和可变性(邪恶)[重复]
【发布时间】:2014-10-25 10:12:26
【问题描述】:

我最近阅读了很多关于Value Types & Reference Types 及其差异的文献。本题围绕值类型的可变性不变性主题。

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

为了阐明对不可变性的理解(为了我自己的理智,为了他人),我在下面展示了这一点:

DateTimeTimeSpan不可变 结构的示例,因为一旦将值分配给实例,该实例值就无法更改,这通过只读属性很明显:

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

然而,在查看 Int32DoubleChar 等原始类型时,不变性可能会令人困惑,因为这些类型似乎是可变的,但我的直觉是,实际上,不变性是通过 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

到目前为止一切顺利;微软似乎在将不变性实现到其值类型中做得很好。但随后我们开始发现坏苹果,以及使可变性看起来不错的细微差别,并使开发人员产生一种虚假的安全感!

我说的是System.Drawing 命名空间中的PointSizeRectangle(以及其他一些)。

突然之间,我们获得了通过属性改变值类型的能力,我有一个理论来解释为什么这是可能的;以下面的代码为例

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);

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

  1. Microsoft 只是想让这些结构的使用变得更容易。
  2. 它们可与本机 GDI/GDI+ 调用互操作,因此它们的行为是围绕其本机 C/C++ 对应物设计的。

最后是我的问题:

  1. 我是否完全涵盖并理解了不变性和可变性?
  2. 开发人员是否应该将构建不可变结构作为一项规则?
  3. 什么时候可以构建可变结构?

【问题讨论】:

标签: c# .net struct immutability mutable


【解决方案1】:

可变性问题不是值与引用类型的问题。两者都有例子。以System.String 作为不可变类的示例以及您的System.Drawing.Point 示例作为可变结构的示例。

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

【讨论】:

    【解决方案2】:

    嗯...这可能很快就会关闭,但这是我对此的看法。

    1. 是的,您似乎正在理解不变性与可变性。
    2. 应该是一个大词。开发人员应该意识到这些差异,足够关心他们的行业,并有常识问自己:我需要从这个特定的结构中得到什么。
    3. 可以接受吗?我猜你什么时候需要它。 你什么时候需要这个问题完全不同。

    通常你使用结构来保存一些属性或原始类型。有一些文章介绍了您的结构中应该和不应该有什么,以便它们在堆或堆栈上结束,但这超出了这里的范围。
    如果您有令人信服的理由使用可变结构,并且将其记录下来以便下一个开发人员知道原因,那没关系。
    相反,如果您不在乎,并且文档不在您的列表中,那么可接受与否并不重要:)。

    【讨论】:

      猜你喜欢
      • 2010-10-01
      • 2011-02-02
      • 1970-01-01
      • 2018-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-11
      相关资源
      最近更新 更多