改变结构中的各种值(它们是多么不可变?)

时间:2011-12-09 12:03:51

标签: c# struct immutability

我一直在阅读关于结构的广泛阅读,我对你在哪里使用它们有一个很好的理解。有一件事让我感到困扰的是,不管我读了多少,我都不明白结构的不变性。

我理解,就像字符串一样,如果你改变它们,你基本上在内存中创建一个全新的对象,但这也适用于结构中的值。例如:

public struct SomeValues
{
    public int AnInt;
    public float AFloat;
    public string AString;
}
public SomeValues[] ArrayOfValues;
private void SomeFunctionThatRunsContinuously()
{
    /*so for every value I change, do I essentially create a whole new instance
      of SomeValues?*/

    for (int i = 0; i < ArrayOfValues.Length; i++)
    {
        //Is this another struct?
        ArrayOfValues[i].AnInt++;

        //And then another again?
        ArrayOfValues[i].AFloat += 0.33f;

        /*I realise adding letters to a string is a horrible idea 
                       -- but is it WORSE to do it in a struct?*/

        ArrayOfValues[i].AString += "s";
    }
}

因此,例如,如果我有一个结构,例如在3D / 2D空间内保持每个人的坐标(坐标是作为何时使用结构的一个例子),并且人们的位置发生变化,在一个两个/三个int结构中更新,从一个数组,是创建新的结构,因为它们是不可变的?

4 个答案:

答案 0 :(得分:0)

结构不是不可变的,除非你将其中的字段设为只读。

public struct SomeValues 
{ 
    public readonly int AnInt; 
    public readonly float AFloat; 
    public readonly string AString; 
} 

答案 1 :(得分:0)

结构不是不可变的。 内存中的新对象不是在您更改时创建的,而是在将其分配给不同的变量或作为参数传递给某个方法时创建的。

答案 2 :(得分:0)

默认情况下,结构不可变,设计结构以使行为不可变是一个非常好的主意。

对于不可变的结构/类来说

  • 不使用公共字段,而是在没有公共设置器的情况下使用属性。私有的setter很好,设置backing-field(来自构造函数)也没关系。
  • 仅允许通过构造函数设置值。
  • 似乎修改结构的方法应该修改它,它们应该返回一个新实例(想想DateTime.AddYears)。

答案 3 :(得分:0)

结构不是一成不变的。虽然有些人似乎认为应该这样,但大多数原因似乎分为三类:

  1. 允许使用struct方法修改“this”,而类方法则不允许;因为在只读上下文中禁止在结构上使用任何和所有方法会很烦人 - 甚至那些实际上不修改“this”的编译器 - 编译器通过临时处理对只读结构的方法调用结构的副本和在这些副本上运行方法;当方法返回时,这些方法可能会消失的任何更改。
  2. 有些人没有意识到结构和类的行为有所不同。
  3. 某些语言特性期望进行代码转换,这些转换对于可变结构可能不如使用不可变结构或类(可变或不可变)那样。

当值类型语义有意义时,当有问题的实体是可变的时,使用结构,尤其是。考虑:

struct fancyRect {public int left,top,width,height; ....other stuff.... };

... then within some code ...
  myList = List<fancyRect>; // Assume this list has been initialized somehow
  fancyRect tempRect = myList[0];
  tempRect.left += 5;
  myList[0] = tempRect;

只需提供信息,就可以完全确定上述代码对myList内容的影响。如果属性可以通过引用公开,允许myList[0].left += 5,那将更清晰,但结构的代码仍然清晰可读。假设tempRect是一个类。上面的代码有什么影响?它有其他影响吗?如何编写它以使其具有与结构相同的语义?