Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么struct可以更改自己的字段?_C#_Struct - Fatal编程技术网

C# 为什么struct可以更改自己的字段?

C# 为什么struct可以更改自己的字段?,c#,struct,C#,Struct,考虑Foo结构,如下所示: struct Foo { public float X; public float Y; public Foo(float x, float y) { this.X = x; this.Y = y; } public void Change(float x) { this.X = x; } } 我理解在构造函数中修改字段,这对我来说是完全合乎逻辑的,我理解结构是值、数字一样的不可变类型 但是,既然不能这样做

考虑Foo结构,如下所示:

struct Foo
{
  public float X;
  public float Y;

  public Foo(float x, float y)
  {
    this.X = x;
    this.Y = y;
  }

  public void Change(float x)
  {
    this.X = x;
  }
}
我理解在构造函数中修改字段,这对我来说是完全合乎逻辑的,我理解结构是值、数字一样的不可变类型

但是,既然不能这样做:

为什么一个人可以使用:

Foo bar = new Foo(1, 2);
bar.Change(5);
编辑:如果结构是可变的,那么为什么在列表中或从属性返回时不能修改它们


你做出了一个关键的错误假设

.NET结构是可变的。您完全可以执行
bar.X=5

您应该将结构设计为不可变的,但是根据您提供的代码,它们是可变的

看看这个问题,了解一下可变结构在哪里会给您带来麻烦。

我在下面的最下面找到了答案:

但是,我仍然不明白为什么编译器在这种情况下允许可变结构。

通常,所有C#struct都不是不可变的,甚至是只读的。因此,您根本无法将结构设计为不可变的

所有结构都是可变的,就像在C++中一样。:)

不变性意味着数据结构在语言级别上是不可变的,而对于C#则不是这样。 我将向您展示如何使用合法的C#语法来打破不变性规则,请注意,NotReallyImmutableFoo.X被声明为一个只读字段

干杯;)

既然做不到

为什么一个人可以使用:

Foo bar = new Foo(1, 2);
bar.Change(5);
你原来的问题实际上无法回答,因为它是建立在一个完全错误的假设上的。这两个代码样本都是完全合法的,因此关于为什么一个是非法的问题是毫无意义的。让我们继续讨论您的后续问题:

如果结构是可变的,那么为什么在列表中或从属性返回时不能修改它们

因为变量是可变的,值是不可变的。

这就是为什么它们被称为“变量”,毕竟,因为它们可以改变

当你说“bar.X=5”时,“bar”是一个局部变量。变量是允许更改的

当你说“bar.Change(5)”时,“bar”是一个局部变量。变量是允许更改的

当您说“myArray[123].X=5”时,“myArray[123]”是数组元素,数组元素是变量。变量是允许更改的

当你说“myDictionary[123].X=5”时,“myDictionary[123]”不是一个变量。该值是从字典返回的,而不是对存储位置的引用。因为这是一个值,而不是一个变量,所以没有任何东西可以改变,所以编译器不允许它改变

一个微妙的点是,当你试图改变一个领域,接收器必须是一个变量。如果它不是一个变量,它就没有意义;很明显,您正在尝试变异一个变量,但没有什么可以变异的。当你调用一个方法时,接收者必须是一个变量,但是如果你有一个值呢?该方法可能不会试图改变任何东西,因此应该允许其成功。如果对结构的方法调用的接收者不是一个变量,那么编译器实际上会做什么,然后它会生成一个新的临时局部变量,并使用该变量调用该方法。所以,如果你说:“myDictionary[123].Change(5);”这和说

var temp = myDictionary[123];
temp.Change(5);
这里“temp”是一个变量,允许使用mutating方法更改临时副本


现在清楚了吗?这里的关键是变量可以改变

net中的结构将分段可变性与赋值时浅拷贝语义以及按值赋值或按引用传递的能力结合起来。然而,在.net中没有一种约定要求类通过引用公开属性,也没有任何.net语言编译器提供这样做的方便方法。一种语言有可能提供这种特性,但有一定的局限性,因为它认识到:

somePoint.X = 5; 点X=5; 可以写成:

void SetXToFive(ref Point it) {it.X = 5;} ... SetXToFive(ref somePoint); void SetXToFive(ref Point it){it.X=5;} ... SetXToFive(参考点); 允许操作
点的代码(通过将其
X
字段设置为5)来自有权访问该点的代码。如果将具有Point类型属性的对象公开一个例程,该例程接受对上述方法的委托,则希望将该属性的字段
X
设置为5的代码可以将该例程的委托传递给
SetXToFive
,然后,例程可以使用任何存储位置调用该点


请注意,与简单地公开对要操纵的对象的引用相比,这种方法的一个优点是
点的所有者将知道操纵它的代码何时完成。如果没有一些编译器晚餐,这种方法通常是一种麻烦而不是好处,但是有了编译器支持,语义可以变得比通过任何其他方法都更清晰。

你的第一句话对我来说很有用。你真的能在某个框架中重现这一点吗?或者这只是一个假设?给公共字段赋值是完全正确的。想想看,你应该能够以某种方式改变它们的值:)结构不是不可变的。语言中没有强迫他们去做的东西。诚然,大多数结构类型是不可变的,但这取决于结构的实现者来实施,不提供Change()之类的方法,也不证明对字段、设置或属性的访问。您的示例struct Foo是可变的。编辑了我的问题,添加了更具体的页脚。语义,语义,语义!我想你的意思是“你应该把结构设计成不可变的”@wesleywiser:的确如此。我的大脑显然跟不上来回的变化。事实上你跟不上。即使您将sruct字段设计为只读字段,我也会修改该特定结构中的值;)编译器允许使用al
var temp = myDictionary[123];
temp.Change(5);
somePoint.X = 5; void SetXToFive(ref Point it) {it.X = 5;} ... SetXToFive(ref somePoint);