【问题标题】:Using properties vs. methods for calculating changing values使用属性与计算变化值的方法
【发布时间】:2012-02-29 21:31:37
【问题描述】:

对于是否使用属性来计算调用值是否有约定?例如,如果我的类包含一个整数列表并且我有一个属性 Average,那么当从列表中添加/删除/修改一个整数时,平均值可能会发生变化,请执行以下操作:

    private int? _ave = null;
    public int Average
    {
        get
        {
            if (_ave == null )
            {
                double accum = 0;
                foreach (int i in myList)
                {
                    accum += i;
                }
                _ave = accum / myList.Count;
                return (int)_ave;
            }
            else
            {
                return (int)_ave;
            }
        }
    }

如果 myList 以可能改变平均值的方式进行修改,则 _ave 设置为 null...

与平均方法调用相比,有什么传统的优势/劣势吗?

我基本上只是想知道对此的约定是什么,因为我正在创建一个具有特定属性的类,这些属性可能只计算一次。我喜欢访问这些属性的类的想法,以便能够访问属性与方法(因为它似乎更具可读性 IMO,将平均值视为属性而不是方法),但我可以看到这个可能会令人费解,尤其是在确保 _ave 正确设置为 null 时。

【问题讨论】:

  • 应该快,不产生任何副作用,永远不要扔。
  • 还要记住,对于某些操作(如上面显示的平均值),如果您使用 List 结构,它已经有一个扩展方法来为您提供此值。
  • @JayP 是的,我知道,我的代码涉及一个更复杂的属性,涉及更详细列表中某些对象的特定出现,但平均示例似乎足以简化问题而不会陷入困境不必要的细节。

标签: c# coding-style conventions


【解决方案1】:

约定是:

  • 如果调用比简单地读取字段并复制其中的值要花费更多时间,请将其设为方法。属性应该快速
  • 如果成员代表类的动作能力,则将其设为方法。
  • 如果对 getter 的调用改变状态,则将其设为方法。属性会在调试器中自动调用,并且在调试程序时让调试器在程序中引入突变会非常令人困惑。
  • 如果调用面对在不寻常的时间被调用时不可靠,则将其设为方法。例如,在构造函数和终结器中使用时,属性需要继续工作。再次考虑调试器;如果您正在调试一个构造函数,那么您应该可以在调试器中检查一个属性,即使它实际上还没有被初始化。
  • 如果调用失败,则将其设为方法。属性不应引发异常。

在您的具体情况下,它是临界值。您第一次执行可能很长的操作,然后缓存结果,因此即使最坏情况下的时间很慢,摊销时间也可能非常快。你正在改变状态,但同样,以一种非破坏性的方式。似乎您可以将其描述为集合的属性,而不是集合的“能力”。我个人倾向于将此作为一种方法,但如果您有充分的理由将其作为一种属性,我不会非常强烈地反击。

关于您的具体实现:我更倾向于使用 64 位整数作为累加器,而不是 64 位双精度数;与 long 的 64 位相比,double 只有 53 位的整数精度。

【讨论】:

  • 我完全同意这一点,但是在“大部分时间”调用很快(即它已经被计算)但“偶尔”即对对象它必须再次计算,这就是我正在努力解决的问题。
  • @NominSim:我添加了一些额外的想法。
  • 谢谢,是的,我将“平均”示例作为一个示例,为了不让问题陷入不必要的细节,我的属性涉及一个类似的想法,即可能很长的初始计算,然后是对已计算值的许多后续调用(可能被需要重新计算值的罕见更改中断)
【解决方案2】:

微软对使用方法的建议:

使用方法

  • 如果调用有副作用
  • 如果每次调用返回不同的值
  • 如果通话时间较长
  • 如果操作需要参数(索引器除外)

如果计算的值是对象的属性,则使用属性。

在您的情况下,我认为具有隐式延迟计算的属性将是不错的选择。

【讨论】:

    【解决方案3】:

    是的... get 访问器不应该以任何方式修改对象的状态。返回的值当然可以计算出来,而且你可能有大量的代码。但简单地访问一个值根本不应该影响包含实例的状态。

    在这种特殊情况下,为什么不在构造类实例时计算所有内容呢?或者提供一个专门的方法来强制类这样做。

    现在我想可能存在非常具体的情况,这种行为是可以的。这可能是其中之一。但是如果没有看到其余的代码(以及它的使用方式),就无法分辨。

    【讨论】:

    • 我真正质疑的是 get 访问器中代码的数量/程度,显然 get 访问器不应该修改对象的状态。
    • >> 是的... get 访问器不应该以任何方式修改对象的状态。唯一的例外是惰性计算 - 当计算结果存储在对象的字段中,然后用于进一步调用时。
    • 我还可以补充一点,该属性旨在立即返回值,因此当您调用 .Average 之类的内容时,您假设它已经被计算过了。你永远不会认为这个属性实际上在做某事。所以方法是做某事的动作,而属性只是返回计算值。但是,可能存在计算 smth 的属性。如果您有一些可以快速计算的值,可能会被缓存,并且开发人员永远不会注意到这些属性正在做某事。他会认为它们已经被计算过了。就像在这种情况下
    • 我的问题是,是否有约定在大多数情况下属性值不会改变并因此可以立即返回,但在初始计算(以及罕见的重新计算)时可能需要一段时间。
    猜你喜欢
    • 2022-01-04
    • 2020-01-08
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    • 2017-11-16
    • 1970-01-01
    • 2023-03-19
    • 2011-09-12
    相关资源
    最近更新 更多