Why use simple properties instead of fields in C#?
Possible Duplicates:
Should I use public properties and private fields or public fields for data?
Difference between Automatic Properties and public field in C# 3.0
人们似乎固执己见地坚持在土地上使用公共财产,但为什么在简单财产的情况下如此重要?
如何
1
| public int Foo { get; set; } |
与…大不相同
?
从我的头脑中,我能想到这两者之间的一些实际差异:
- 使用反射访问成员(很少,而且大多数合适的反射算法将解释差异)
- 第二个条目允许您使用字段作为ref和out参数的有效参数,这似乎是使用字段版本的优势。
- 字段在远程处理中不起作用(可能,我从未使用过远程处理,但我想它们不会)?
除了这些非常罕见的情况外,将foo更改为计算属性之后会导致0行代码发生更改。
- 实际上,将变量更改为属性是一种破坏性的更改。
- 当然,它会破坏现有的DLL,但不会破坏代码。
- 超级重复:stackoverflow.com/questions/1277572/…,stackoverflow.com/questions/1216958/…,与stackoverflow.com/questions/295104/…和stackoverflow.com/questions/205568/…相关。我们真的需要另一个吗?
- @啊,罗诺特,我同意,我要旗子把这个关上。
- 使用属性比使用字段更可取,因为您可以更改get和set块中的语句,而无需更改依赖于属性的类。
使用属性有两个明显的优势:
- 如果以后需要额外的逻辑,它允许版本控制。向getter或setter添加逻辑不会破坏现有代码。
- 它允许数据绑定正常工作(大多数数据绑定框架不与字段一起工作)。
此外,几乎没有缺点。像这样简单的自动属性是由JIT编译器内联的,因此没有理由不使用它们。
此外,您还提到:
Other than these fairly rare cases, changing Foo to be a computed property later results in 0 lines of code changed.
这不需要更改代码,但它确实强制您重新编译所有代码。从字段更改为属性是一个破坏性的API更改,它将要求重新编译引用程序集的任何程序集。通过使其成为一个自动属性,您可以只发送一个新的二进制文件,并保持API的兼容性。这就是我上面提到的"版本控制"优势…
- 我倾向于同意,您可能不想使用属性的唯一原因是处理ref或out要求,尽管您可以轻松地生成一个要使用的临时变量,然后将该属性设置为该变量,该变量稍后将被处理。
- 使用属性比使用字段更可取,因为您可以更改get和set块中的语句,而无需更改依赖于属性的类。
- 如果在分配之前使用set块检查该值,则很难解释客户机代码:person.Name =""; print(person)可能建议更改名称,但setter可能会阻止更改。总之,使用"设置块"在我看来是一个反特性。
一个很好的原因是您可以改变get/set的可访问性。
1
| public int Foo {get; protected set;} |
- 哇,我没意识到这一点。+ 1,谢谢
- 虽然只应在构造函数中设置的字段的readonly修饰符可以解决许多这样做会有帮助的情况。而且,现在是未来了,您可以执行public int Foo { get; }(自动实现只获取readonly字段支持的属性)。
- 我猜。对于以后的更改,您可以将变量属性改为字段。但是,有没有一个好的实践来定义变量或属性之间的差异呢?
属性是一种语言元素,逻辑上表示由类建模的对象的属性。阶级汽车是汽车的模型;颜色是汽车的属性;因此,颜色是汽车的属性。
字段是表示类的实现细节的语言元素。您的汽车没有"颜色字段",因此程序对汽车的表示不应公开一个名为"颜色"的字段。它可能包含私有实现细节,其中属性颜色由字段实现,但这是私有实现细节,而不是模型的公共可访问部分。
- 我更喜欢这个解释,因为它并不否认属性实际上是语言的一个冗余特性,如果你把这个逻辑语义从图片中去掉的话。唯一支持的是反射(如Reed提到的数据绑定)。但这可以通过字段上的注释(属性)实现。
- @奥杜:几乎语言的每一个特征都是多余的。例如,方法是不必要的;方法可能只是用lambda初始化的委托类型的字段。冗余常常被认为是一件坏事,但它根本不是;冗余使事情更容易理解。正如我在答案中所指出的,有两个特性,属性和字段,让我们能够巧妙地与读者沟通,无论成员在语义上是重要的还是仅仅是类型的一种机制。
- 为什么不以"公共字段是…"和"私有字段是…"开头?那么还有什么理由可以拥有财产呢?
- @Michawiedenmann:许多属性不能用字段替换。
- @埃里克:如果字段是一个实现细节,为什么我们可以公开它?
- @卡罗尔:仅仅因为你能做一件事并不意味着你应该做。C中的最佳实践是使字段成为私有实现细节,并使用属性来表示业务概念。
- @Ericlippert:如果您有机会在不限制现有代码破坏的情况下重新设计C,您会允许类中的公共字段吗?还有保护区?
- @卢卡克雷蒙尼:在这个反事实的世界里,有很多事情我会解决,但这不是其中之一。有一些语言特性是真正危险的误导性的;那些看起来应该工作的代码是行不通的。有一些语言特性是混乱和冗余的。语言中的安全特性的设计应使编写错误的程序变得困难;防止人们违反次要的最佳实践规则,使其非法通常不是最佳的时间和精力利用。
- @埃里克:你经常说功能不是默认实现的,C团队需要一个理由来实现它们。他们并没有从拥有所有特性的C开始,然后出于一些好的原因将其中的一些特性去掉。为字段指定访问修饰符的能力似乎是一个特性。它看起来是默认实现的,现在需要额外的工作来删除它。如果它不是真的,但我们仍然同意没有真正的案例来使用它,那么为什么要设计、指定、实现、测试、记录和运输它呢?
- @卡罗尔:嗯,有利弊。例如:C语言必须能够与其他.NET语言进行良好的交互,而且必须熟悉Java和C++的用户。在某些情况下,由于性能原因,您希望直接访问结构域,尤其是用于与C++互操作性的普通旧数据结构。而且不能通过引用传递属性,所以并不是说它们没有零用例。但是请注意,我命名的所有这些用例都意味着字段是机制。
您可以使属性成为虚拟的,并在派生类中重写它们的实现。在许多将对象包装在生成的代理类中的库中,这是一个重要因素,例如nhibernate实现延迟加载的方式。这在野外是不可能的。
- 这完全否认了可以将字段包装在访问器变异器中并获得相同的特性。这一点尤其正确,因为属性通常这样做,它们包装一个字段。(只要它们不是自动属性)。而BAM,回到原点,属性是无用的。
- @v.oddou,甚至是技术上的自动属性,只包装编译器生成的字段。只是语法糖!
主要是因为惯例。
唯一可靠的理由是,如果以后需要从字段更改为属性,则需要重新编译引用您的所有程序集。
偶尔也会有反省,但很少。某些序列化类型基于属性。