【问题标题】:Is a Property necessary if the field is used only for internal logic?如果字段仅用于内部逻辑,是否需要属性?
【发布时间】:2017-09-21 22:25:28
【问题描述】:

我知道如何使用属性来公开字段,有什么好处等等。我想了解的(我已经搜索了很多)是:

是否每个字段都需要始终具有包装属性,即使它不需要公开并且仅用于内部逻辑?

我认为答案是肯定的,因为即使在某些内部逻辑中对其进行了修改,新值仍然需要验证。

如果答案是肯定的,这就是为什么属性具有公共获取和私有设置如此普遍的原因吗?

编辑:感谢您给我的所有答案,但大多数都与我的问题无关,你们中的大多数人都在谈论大而复杂的类,我的简单问题是,我是否应该有一个包装属性对于仅在其类内部使用且不需要公开的字段。

编辑 2:一些答案提出了一些可以接受为否的答案,表明如果不需要逻辑,则不应使用属性

编辑 3:谢谢大家,我重读了大部分 cmets,它开始变得有意义,就像往常一样 :)

【问题讨论】:

  • 好吧,您可以选择在每种情况下如何使用字段。如果你有一些不同的内部逻辑来归档你可以避免使用属性并添加一些验证方法,当然,属性是方法,你可以将字段包装到几个属性,但我认为它是多余和不清楚的
  • 不,除非您需要在 setter 或 getter 中放入一些逻辑(尽管 getter 不太可能),否则不要将其设为属性。如果班级太大以至于没有人可以跟踪所有内容并且您需要彼此隐藏部分,那么它太大并且做得太多。将其重构为两个或更多易于管理的类。
  • 大多数情况下,在处理类内部使用的私有数据或常量时,您希望使用字段,并且如果对字段的访问应该暴露在类。
  • 当你应该使用属性而不是方法时,它们是一些好方法:answer 1answer 2

标签: c# oop


【解决方案1】:

这不是其中一个问题,如果你弄错了就会造成很大的损害。

也就是说,不,除非您需要在 setter 或 getter 中放置一些逻辑,否则不要将其设为属性,而且您可能不需要这样做。不要添加无用的代码。

“字段不好”不是目的。事实上,这是无稽之谈。字段的存在是有原因的。

如果班级太大以至于没有人可以跟踪所有内容,并且您需要彼此隐藏部分,那就太大了,而且做得太多。将其重构为两个或更多易于管理的类。

很多时候,随着一个大类的增长(大多数情况下自然不会有非常紧密的关注点,比如一个主要的视图模型,或者过去糟糕的窗口或窗体),我们发现自己在编写一些小的“子系统” " 在类中具有一个或两个具有 set 和/或 get 块中的逻辑的字段。这是重构为具有干净接口的单独小类的候选者,这是一个易于重用的逻辑和状态球,它的内部没有与你的大类的内部混合。给大类一个小帮手类的私有副本。拖放代码就是一个浮现在脑海中的例子。

这是一个经典的进程:

  1. 我将添加一个标志
  2. 我昨天添加的那个标志必须是一个枚举
  3. 带有标志
  4. 等等,我只是复制并粘贴了一段代码。把它放在旗帜上的二传手中。
  5. 还有一个帮助...两个辅助方法。
  6. 让我们在这个烂摊子周围加上#region,这样我就不用看它了。
  7. 我们将不得不将整个混乱复制并粘贴到另一个类中。好东西都在一个地方!
  8. 并非全部集中在一处。
  9. 我的经理拿那件有趣的袖子夹克做什么?

如果您达到第 7 阶段,就该进行干预了。

私有属性只是随着时间的推移可能会变成有害代码气味的第一个微小气味。它们并不邪恶,但它们可能表明您的代码显示出在错误的轴上增长的趋势。

更新

关于内部与外部验证

很多时候,一个类需要能够打破自己的规则,并且干净、直接地这样做。例如,一个属性/字段的验证通常取决于其他属性/字段的值(日期范围等)。你的类的内部应该能够以任意顺序设置它们,而不需要任何有趣的事情(有时你会看到“_disableValidation”标志来解决这个问题——代码味道)。在类内部,验证应该是自愿的,并且类应该保持足够简单,这样就不会出现问题。一个类需要允许自己暂时将自己置于无效状态,同时禁止或控制任何外部代码将其置于无效状态的方式。也许如果外部代码将其置于无效状态,这是代码允许的,但它会驱动 UI,从而困扰用户。你不希望有奇怪的标志来让你的构造函数在不弹出消息框或其他东西的情况下完成它的工作。

有时,班级需要在自己家中的私密空间中四处奔波。验证应针对类外部代码的输入。

【讨论】:

  • 谢谢,我还有一个问题几乎跟上一个问题差不多。如果一个字段需要在赋值之前进行验证,即使它来自内部逻辑,它是否应该通过一个属性,即使它不需要暴露给外部世界,还是应该有一个适当的逻辑它正在被分配。假设我们有 x 字段,并且我们想在方法 ChangeXValue 中更改其值,验证逻辑(假设需要)应该进入该方法还是 X 属性?
  • @Darkbound 好问题。很多时候,一个类需要能够打破它自己的规则。例如,一个属性/字段的验证通常取决于其他属性/字段的值(日期范围等)。您的类内部应该能够以任意顺序设置它们,而无需任何有趣的事情(有时您会看到“_disableValidation”标志来解决这个问题——代码异味)。在类内部,验证应该是自愿的,并且类应该保持足够简单,这样就不会出现问题。一个类需要允许自己暂时处于无效状态,而...
  • @Darkbound ...禁止或控制任何外部代码将其置于无效状态的方式。程序员的一部分工作是让一个班级在自己家里的隐私中安全地在 nekkid 周围跑来跑去。验证应针对类外部代码的输入。
  • 如果我理解正确,就不需要内部验证,这意味着在使用内部逻辑时,我们应该只使用字段和属性,而不应该是内部逻辑的一部分?
  • @Darkbound 你绝对可以引用我的话!谢谢。我会毫不犹豫地说从不需要内部验证——永远不要说永远。但每次我这样做我都会后悔。
【解决方案2】:

没有必要这样做,但是通过使用属性而不是字段,您会更加灵活,因为您可以预处理获取和设置变量。将已在其他代码中使用的字段更改为属性可能是一项重大更改。因此,如果您不知道该选择什么,请选择一个安全且最灵活的房产。

【讨论】:

    【解决方案3】:

    YAGNI

    如果您不使用属性 - 不要创建它。
    如果您需要更改字段的某些方式或更改其创建/更新方式的逻辑,您将能够在没有属性的情况下进行操作。

    因为您不公开它 - 您无需担心会破坏其他代码。

    如果您有一些实例化/更新该字段的“复杂”逻辑 - 为它创建一个私有方法。

    在 setter 中添加一些“额外”逻辑,甚至值得在 getter 上添加一些“副作用”——可能会导致一些奇怪的行为或错误,因为当我初始化类时

    var order = new Order
    {
        Id = 1001,
        Reference = "Reference one",
        CustomerId = 2001        
    }
    

    我不希望分配CustomerId 会导致某些数据库查询或某些复杂逻辑的执行。而是

    var order = new Order
    {
        Id = 1001,
        Reference = "Reference one"      
    };
    order.SetCustomer(customerid);
    

    【讨论】:

    • 投反对票的人,你能提供改进答案的建议吗?
    • 我不是反对者,但这并不能真正解决 OP 对私有字段是否应该改为绳索的担忧。
    猜你喜欢
    • 2021-03-28
    • 2011-03-05
    • 1970-01-01
    • 2018-07-14
    • 1970-01-01
    • 2013-03-12
    • 2018-05-21
    • 1970-01-01
    相关资源
    最近更新 更多