关于c#:受保护的成员/领域真的那么糟糕吗?

Are protected members/fields really that bad?

现在,如果您阅读msdnforc中的命名约定,您会注意到它指出属性总是优先于公共和受保护的字段。有些人甚至告诉我,你不应该使用公共或受保护的土地。现在我同意我还没有找到一个理由,我需要一个公共领域,但保护领域真的那么糟糕吗?

我可以看到,如果您需要确保在获取/设置值时执行某些验证检查,但是在我看来,很多时候似乎只是额外的开销。我是说,假设我有一个类游戏项,其中包含basename、prefixname和suffixname字段。为什么我要承担创建属性(C#或访问器方法的开销,以及可能发生的性能损失(如果我对应用程序中的每个字段都这样做,我确信它加起来不会太多,特别是在某些语言(如PHP中)或某些具有性能的应用程序中,这是关键的,就像电子游戏?


Are protected members/fields really that bad?

不,是这样,更糟。

一旦一个成员比private更容易访问,您就可以向其他类保证该成员的行为。因为一个字段是完全不受控制的,所以将它"放在野外"将打开您的类和继承自类或与类交互的类,从而增加bug风险。无法知道字段何时更改,也无法控制字段的更改者或更改内容。

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

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

1
protected object MyProperty { get; }

如果你必须让它读/写,不要。如果你真的,真的必须让它读-写,重新考虑你的设计。如果你还需要读写,向你的同事道歉,不要再这样做了:)

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

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


好的,投票否决时间。

  • 首先,属性永远不会影响性能(前提是它们不做太多)。其他人都这么说,我同意。

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

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

  • 他们听起来像是"威望之争"。如果msdn说了,或者某个大家都喜欢的著名开发人员或作者说了,那一定是这样。

  • 它们基于这样一个理念,即数据结构具有许多不一致的状态,必须保护它们不受漫游或放置到这些状态中。因为(在我看来)数据结构在当前的教学中被过分强调,所以它们通常需要这些保护。更可取的是最小化数据结构,使其趋向于规范化,而不具有不一致的状态。然后,如果一个类的成员被更改,那么它只是被更改,而不是被损坏。毕竟,很多好的软件都是用C语言编写的,而这并没有因为缺少保护而遭受巨大的损失。

  • 它们基于极端的防御编码。它基于这样一个理念:你的类将在一个没有人可以信任其他代码的世界中使用,而不是欺骗你的东西。我相信有些情况下这是真的,但我从未见过。我所看到的情况是,为了绕过不需要的保护,使事情变得非常复杂,并试图保护数据结构的一致性,这些数据结构过于复杂和不规范。


关于字段与属性,我可以考虑在公共接口中优先使用属性的两个原因(受保护的也是公共的,从某种意义上说,除了您的类之外,其他人也可以看到它)。

  • 通过公开属性,可以隐藏实现。它还允许您在不更改使用它的代码的情况下更改实现(例如,如果您决定更改数据存储在类中的方式)

  • 许多使用反射处理类的工具只关注属性(例如,我认为一些用于序列化的库就是这样工作的)。一致地使用属性使使用这些标准.NET工具更加容易。

关于日常开支:

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

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

    1
    protected int SomeProperty { get; set; }

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


公共字段和/或受保护字段是不好的,因为它们可以在声明类之外进行操作,而无需验证;因此可以说它们破坏了面向对象编程的封装原则。

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

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


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

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

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


我同意只读属性答案。但要在这里扮演魔鬼的拥护者,这真的取决于你在做什么。我很高兴地承认,我一直在和公众成员一起编写代码(我也不发表评论,不遵守指导原则,也不做任何手续)。

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