gpt4 book ai didi

c# - 为什么 Point.Offset() 没有在只读结构中给出编译器错误?

转载 作者:太空狗 更新时间:2023-10-30 00:29:40 25 4
gpt4 key购买 nike

也许我误解了只读结构的概念,但我认为这段代码不应该编译:

public readonly struct TwoPoints
{
private readonly Point one;
private readonly Point two;

void Foo()
{
// compiler error: Error CS1648 Members of readonly field 'TwoPoints.one'
// cannot be modified (except in a constructor or a variable initializer)
one.X = 5;

//no compiler error! (and one is not changed)
one.Offset(5, 5);
}
}

(我使用的是 C# 7.3。)我错过了什么吗?

最佳答案

编译器无法确定 Offset 方法会改变 Point 结构成员。但是,readonly 结构字段与非只读结构字段的处理方式不同。考虑这个(不是只读的)结构:

public struct TwoPoints {
private readonly Point one;
private Point two;

public void Foo() {
one.Offset(5, 5);
Console.WriteLine(one.X); // 0
two.Offset(5, 5);
Console.WriteLine(two.X); // 5
}
}

one 字段是只读的,但 two 不是。现在,当您在 readonly 结构字段上调用方法时,会将结构的 副本 作为 this 传递给该方法。如果方法改变了结构成员——那么这个副本成员就会改变。出于这个原因,您在调用方法后不会观察到 one 的任何更改 - 它没有更改,但复制了。

two 字段不是只读的,结构本身(不是复制)被传递给 Offset 方法,所以如果方法改变了成员——你可以观察到它们在方法之后改变了打电话。

因此,这是允许的,因为它不会破坏 readonly struct 的不变性契约。 readonly struct 的所有字段都应该是readonly,在readonly struct 字段上调用的方法不能改变它,它们只能改变一个副本。

如果您对此的“官方来源”感兴趣 - 规范(7.6.4 成员(member)访问权限)说明:

If T is a struct-type and I identifies an instance field of that struct-type:

• If E is a value, or if the field is readonly and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the field I in the struct instance given by E.

• Otherwise, the result is a variable, namely the field I in the struct instance given by E.

T这里是目标类型,I是被访问的成员。

第一部分说如果我们在构造函数之外访问结构的实例只读字段,结果是。在第二种情况下,实例字段不是只读的 - 结果是变量

然后“7.5.5 函数成员调用”一节说(这里的E是实例表达式,所以比如上面的onetwo) :

• If M is an instance function member declared in a value-type:

If E is not classified as a variable, then a temporary local variable of E’s type is created and the value of E is assigned to that variable. E is then reclassified as a reference to that temporary local variable. The temporary variable is accessible as this within M, but not in any other way. Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.

正如我们在上面看到的,readonly struct field access results in a value, not a variable and so, E 不属于变量。

关于c# - 为什么 Point.Offset() 没有在只读结构中给出编译器错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50527421/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com