C# 更改结构中的各种值(它们有多不可变?)

C# 更改结构中的各种值(它们有多不可变?),c#,struct,immutability,C#,Struct,Immutability,我已经广泛阅读了structs,我对在哪里使用structs有一个很好的理解。尽管有一件事困扰着我,不管我读了多少关于它的书,我都不理解结构的不变性 我理解,就像字符串一样,如果更改它们,实际上就是在内存中创建一个全新的对象,但这是否也适用于结构中的值。例如: public struct SomeValues { public int AnInt; public float AFloat; public string AString; } public SomeValue

我已经广泛阅读了structs,我对在哪里使用structs有一个很好的理解。尽管有一件事困扰着我,不管我读了多少关于它的书,我都不理解结构的不变性

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

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";
    }
}
public结构SomeValues
{
公共信息;
公众漂浮;
公共字符串搜索;
}
public SomeValues[]ArrayOfValues;
private void持续运行的函数()
{
/*因此,对于我更改的每个值,我是否本质上创建了一个全新的实例
有什么价值*/
for(int i=0;i

举个例子,如果我有一个结构,比如说,它保存着3D/2D空间中每个人的坐标(坐标是作为何时使用结构的一个例子给出的),而人的位置在一个2/3 int结构中改变并更新,可能来自一个数组,创建新结构是因为它们是不可变的吗?

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

public struct SomeValues 
{ 
    public readonly int AnInt; 
    public readonly float AFloat; 
    public readonly string AString; 
} 
结构不是不变的。 内存中的新对象不是在您更改它时创建的,而是在您将它分配给不同的变量或作为参数传递给某个方法时创建的。

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

所以对于不可变的结构/类

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

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

  • 结构方法允许修改“this”,而类方法不允许;由于禁止在只读上下文中使用结构上的任何和所有方法(即使是那些实际上没有修改“this”的方法)会很烦人,编译器会通过制作结构的临时副本并在这些副本上运行方法来处理只读结构上的方法调用;当这些方法返回时,这些方法所做的任何更改都可能消失。
  • 有些人没有意识到结构和类的行为是不同的。
  • 一些语言特性希望进行代码转换,而这些转换对于可变结构可能不如对于不可变结构或类(可变或不可变)那么有效。 当值类型语义有意义时,使用结构,特别是当所讨论的实体是可变的时。考虑:

    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; struct fancyRect{public int left,top,width,height;……其他内容……}; ... 然后在一些代码中。。。 myList=List;//假设此列表已以某种方式初始化 fancyRect tempRect=myList[0]; tempRect.left+=5; myList[0]=tempRect;
    以上代码对myList内容的影响仅凭提供的信息即可完全确定。如果属性可以通过引用公开,允许
    myList[0].left+=5
    ,则会更干净,但结构的代码仍然清晰可读。假设tempRect是一个类。上述代码会产生什么影响?它还会有其他影响吗?如何将其编码为具有与结构相同的语义?

    但如果您有一个引用类型的成员,而该成员没有只读字段,该怎么办?@David-那么您不能将新实例分配给该字段,但您可以(如果没有其他保护)更改现有实例中的值。
    readonly
    声明不会使结构中的非静态字段不可变。如果
    struct1
    struct2
    属于同一类型,则语句
    struct1=struct2
    将变异
    struct1
    的所有公共和私有字段(可能同时,也可能以某种任意顺序),以匹配
    struct2
    的相应字段;结构类型定义中的任何内容都不能更改此行为。结构是可变的。让它们不变是流行的智慧,旨在让新程序员免于麻烦。当然,让自己陷入困境是一个很好的策略,可以让你了解这一切。变异消失!谢谢你,从我所读到的,我被误导到认为他们的“使不可变”是“它是不可变的”。老实说,你的建议更有意义:点击这些障碍,这样你就可以理解它们,然后决定它是否能让你的代码更干净,使其不可变。相关:。对于第1点,有趣的是,我听到了完全相反的说法:“一般来说,我的感觉是属性被高估了,字段被严重低估了”,谢谢,我不知道结构不是不可变的,我只是最近才开始研究字符串,所以这对我来说有点混乱。有些“东西”需要属性而不是字段。在这种情况下,您需要使用属性,以便限制访问(公共读取、私有写入)。这是不可能的。