gpt4 book ai didi

c# - 为什么递增运算符可以在属性上使用,而 ref 不行

转载 作者:太空狗 更新时间:2023-10-29 23:29:10 28 4
gpt4 key购买 nike

假设你有这样一个类

public class Foo
{
public int Bar { get; set; } = 42;
}

如果您尝试将属性作为 ref 参数传递,编译器会发出错误

CS0206 A property or indexer may not be passed as an out or ref parameter

这是可以理解的,因为实际上上例中的属性被编译到 get_Bar()set_Bar() 方法中。但是如果你在属性上使用增量运算符,比如

var foo = new Foo();
foo.Bar++;

它按预期工作。为实现这一点,编译器需要生成如下伪代码:

var foo = new Foo();
int tmp = foo.get_Bar();
tmp++;
foo.set_Bar(tmp);

所以理论上编译器可以为 ref 做类似的事情,比如:

var foo = new Foo();
int tmp = foo.get_Bar();
DoSomething(ref tmp);
foo.set_Bar(tmp);

编译器不这样做是否有技术原因,或者这只是 C# 团队的设计决定?

最佳答案

正如 HansPassant 所说,这是 C# 团队在编写 C# 规范时做出的设计决定,因此您必须询问他们中的一个才能得到正确的答案。

不过,如果我冒险猜测的话,编译器使用 ref 传递属性的魔法数量会导致在幕后发生足够多的不明显操作,从而使解决方案不可取。例如,当前递增/递减属性的工作方式如您所说:程序将属性的支持字段的值分配给临时变量,执行操作,然后将结果重新分配给属性。这是一个简单的过程,没有包含任何困难的概念。

要在幕后执行相同的操作以使用 ref 传递属性,但是,该过程变得更加复杂。当 ref 传递值类型时,通过参数传递的实际值是指向值类型变量的指针。但是,要为属性执行此操作,您必须执行类似于第二个示例的操作。这将导致临时变量的地址,而不是属性本身,被传递给方法。对于试图以某些方式操纵 ref 参数的人来说,这种行为可能会导致一些无法预料且难以理解的后果。

所以我猜测,增量运算符很容易包装,因为它只处理值,而 ref 关键字更复杂,因为它还必须担心范围和内存地址。

编辑: 我想到的另一个原因是,对于字段,被调用方法内的任何操作都会反射(reflect)在字段本身上。这些操作可以被其他线程看到,从而在方法执行期间访问该字段(撇开并发字段可访问性的最佳实践)。

但是,对于参数,在方法返回并且值被复制回来之前,方法内部发生的任何更改都是不可见的。这会导致字段和属性之间的行为不一致,其原因并不明显。

(就我个人而言,我认为这是不支持属性上的 ref 的更可能的原因。)

关于c# - 为什么递增运算符可以在属性上使用,而 ref 不行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40828584/

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