38

现在,如果您阅读 MSDN for C# 中的命名约定,您会注意到它声明属性始终优先于公共和受保护字段。有些人甚至告诉我,你永远不应该使用公共或受保护的字段。现在我同意我还没有找到需要公共字段但受保护字段真的那么糟糕的原因吗?

如果您需要确保在获取/设置值时执行某些验证检查,我可以看到它,但是在我看来,很多时候这似乎只是额外的开销。我的意思是说我有一个 GameItem 类,其中包含 baseName、prefixName 和 suffixName 字段。为什么我要承担创建属性C#(某些语言PHP(例如游戏)或某些性能至关重要的应用程序)?

4

6 回答 6

94

受保护的成员/字段真的那么糟糕吗?

不,他们是方式,方式更糟。

只要一个成员比 更易于访问private,您就可以向其他类保证该成员的行为方式。由于一个字段是完全不受控制的,因此将其“放在野外”会打开您的类以及从您的类继承或与您的类交互的类,从而带来更高的错误风险。无法知道字段何时更改,也无法控制谁或什么更改了它。

如果现在或将来的某个时候,您的任何代码曾经依赖于某个字段的某个特定值,那么您现在必须添加有效性检查和回退逻辑,以防它不是预期值 - 您使用它的每个地方。当你本可以把它变成一个该死的财产时,这是一个巨大的浪费;)

与派生类共享信息的最佳方式是只读属性

protected object MyProperty { get; }

如果您绝对必须使其读/写,请不要。如果你真的,真的必须让它读写,重新考虑你的设计。如果您仍然需要它进行读写,请向您的同事道歉并且不要再这样做了:)

许多开发人员相信——并且会告诉你——这过于严格。确实,您可以过得很好,而不必如此严格。但是采用这种方法将帮助您从勉强应付到非常强大的软件。您将花费更少的时间来修复错误。

关于性能的任何担忧 - 不要。我保证,在你的整个职业生涯中,你永远不会写出如此快的代码,以至于瓶颈是调用堆栈本身。

于 2010-07-05T23:25:59.133 回答
34

好的,投票时间。

  • 首先,属性永远不会损害性能(只要它们不做太多)。其他人都是这么说的,我同意。

  • 另一点是属性很好,因为您可以在其中放置断点以捕获获取/设置事件并找出它们的来源。

其余的论点以这种方式困扰着我:

  • 它们听起来像是“声望的争论”。如果 MSDN 这么说,或者大家都喜欢的著名开发者或作者这么说,那一定是这样。

  • 它们基于这样的想法,即数据结构具有许多不一致的状态,并且必须防止徘徊或被置于这些状态中。由于(在我看来)数据结构在当前教学中被过分强调,因此通常它们确实需要这些保护。更可取的是最小化数据结构,使其趋于规范化并且不具有不一致的状态。然后,如果一个类的成员发生了变化,它只是被改变了,而不是被损坏了。毕竟,不知何故,很多好的软件都是用 C 语言编写的,并且没有因为缺乏保护而受到严重影响。

  • 它们基于极端的防御性编码。它基于这样的想法,即您的类将用于一个无法信任其他人的代码不会使您的东西变得笨拙的世界。我敢肯定在某些情况下这是真的,但从未见过。我看到的情况是,事情变得非常复杂,以绕过不需要的保护,并试图保护过于复杂和非规范化的数据结构的一致性。

于 2010-07-05T23:55:42.523 回答
6

关于字段与属性,我可以想到两个首选公共接口中的属性的原因(受保护的也是公共的,因为除了您的班级以外的其他人可以看到它)。

  • 公开属性为您提供了一种隐藏实现的方法。它还允许您更改实现而不更改使用它的代码(例如,如果您决定更改数据在类中的存储方式)

  • 许多使用反射处理类的工具只关注属性(例如,我认为一些用于序列化的库以这种方式工作)。始终如一地使用属性可以更轻松地使用这些标准的 .NET 工具。

关于开销:

  • 如果 getter/setter 是通常的一行代码,它只是简单地读取/设置字段的值,那么 JIT 应该能够内联调用,因此没有性能开销。

  • 当您使用自动实现的属性(C# 3.0 和更高版本)时,语法开销会大大减少,所以我认为这不是问题:

    protected int SomeProperty { get; set; }
    

    事实上,这使您可以很容易地使例如set受保护和公开,因此这甚至比使用字段更优雅。get

于 2010-07-05T23:27:10.410 回答
6

公共和/或受保护的字段是不好的,因为它们可以从声明类的外部未经验证地进行操作;因此可以说它们打破了面向对象编程的封装原则。

当你失去封装时,你失去了声明类的契约;您不能保证该类的行为符合预期或预期。

使用属性或方法访问字段使您能够维护封装,并履行声明类的约定。

于 2010-07-05T23:27:33.610 回答
0

这实际上取决于您的类是数据类还是行为类。

如果您将行为和数据分开,则可以公开数据类的数据,只要它们没有行为即可。

如果该类是行为类,则它不应公开任何数据。

于 2010-07-06T10:27:07.727 回答
0

我同意只读属性的答案。但是在这里扮演魔鬼的拥护者,这真的取决于你在做什么。我很乐意承认我一直与公众成员一起编写代码(我也不发表评论、遵循指南或任何形式)。

但当我在工作时,情况就不同了。

于 2010-07-05T23:51:01.270 回答