C#字段与属性的区别

7

可能重复:
C#中属性和字段的区别

我以为基本属性({ get; set; })与公共字段相同,只是能够在不破坏二进制兼容性的情况下更改它们。根据我在这里得到的答案https://dev59.com/I2oy5IYBdhLWcg3wKq4S#8735303,我发现属性也有一个缺点。如果它们是值类型,则无法通过引用访问它们。为什么会这样,还有哪些区别?


这里是答案:https://dev59.com/qHRB5IYBdhLWcg3wWF8H - Dipu Raj
5
那是一个谬误。属性不能通过引用访问,就这样。你犯了常见错误,混淆了引用传递和引用类型。 - Noldorin
1
也就是说,默认情况下按值传递引用类型的引用。对于引用类型和值类型,始终使用 refout 关键字进行引用传递。 - diggingforfire
@DipuRaj 我认为这个问题不是完全重复的,因为它询问了为什么会出现所提到的行为,而那个问题没有。 - Baruch
2个回答

14
我发现属性也有一个缺点。如果它们是值类型,就无法通过引用访问它们。为什么呢?因为在底层,属性只是一个方法。如果查看 IL,您会看到像 get_PropertyNameset_PropertyName 这样的方法。问题在于,为了支持使用引用工作,您需要能够返回方法的引用。
public ref T MyProperty
{
    get
    {
         return ref _underlyingField;
    }
}

更新: 从C# 7.0开始,可以使用上述描述的语法实现此操作。

之前的答案剩余部分:

当然,在CLR中是完全可能的;但不是由C#语言公开的。

虽然这是可能的,但CLR需要进行一些调整才能保持可验证性。该属性的语法也必须支持它。

然而,这有用吗? 正如您所说,一个字段可以做到这一点。如果需要,请使用字段。支持它需要大量的工作。可能只有极少数情况是适当的,而在第一次使用字段可能更好。


4

属性只是对getX()setX()方法语法的简单封装。它看起来和行为类似于字段,但实际上只是两个方法。引入自动属性的原因是为了避免重复创建字段并且为该属性创建标准getter和setter,并使得更改实现而不更改接口变得更加简单。

如果它们是值类型,则无法通过引用进行访问的原因是值类型通常在堆栈上,因为你只是调用方法。必须调用属性中的getter并将返回的值推送到堆栈上才能被引用。


7
-1是为了防止传播关于值类型在堆栈中的错误观念(即便加上“一般”一词)。如果属性(或字段)是一个类,它就不会在堆栈中。 - Jon Skeet
@JonSkeet 我认为他在谈论getter的返回值,它首先会进入一个寄存器,然后可能会进入堆栈,以便获得可以引用的地址。 - CodesInChaos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接