何时使用属性而不是函数

51

这可能是个人偏好的问题,但在您的代码中何时使用属性而不是函数呢?

例如,要获取错误日志,我可以使用以下代码:

string GetErrorLog()
{
      return m_ErrorLog;
}

或者我可以

string ErrorLog
{
     get { return m_ErrorLog; }
}

你如何决定使用哪个?我似乎在使用上不一致,我正在寻找一个好的经验法则。谢谢。


至少3个答案在http://stackoverflow.com/search?q=c%23+properties中的重复。 - ax.
6个回答

77

如果以下条件成立,我倾向于使用属性:

  • 属性将返回单个逻辑值
  • 很少或根本没有涉及逻辑(通常只返回一个值,或执行一个小的检查/返回值)

如果以下条件成立,我倾向于使用方法:

  • 获取值需要大量的工作-例如:从数据库中获取它,或者从可能需要"时间"的其他地方获取值
  • 有相当多的逻辑涉及到获取或设置值

此外,我建议查看Microsoft的属性使用设计指南。他们建议:

当成员是逻辑数据成员时,请使用属性。

当操作是转换(例如Object.ToString)时,请使用方法。

  • 如果操作足够昂贵,以至于您希望向用户传达他们应该考虑缓存结果,请使用方法。
  • 使用get访问器获取属性值会产生可观察的副作用。
  • 连续两次调用成员会产生不同的结果。
  • 执行顺序很重要。请注意,类型的属性应该能够按任何顺序设置和检索。
  • 成员是静态的,但返回一个可以更改的值。
  • 成员返回数组。返回数组的属性可能会非常误导人。通常需要返回内部数组的副本,以便用户无法更改内部状态。这与用户可能轻松地将其视为索引属性有关,导致代码效率低下。在以下代码示例中,每次调用Methods属性都会创建数组的副本。因此,在以下循环中将创建2n+1个数组的副本。

2
我想补充一点,你的方法应该只有一个职责。不要创建大量的方法,这些方法会做很多不同的事情。将每个不同的工作拆分为私有方法,甚至是另一个类中的方法。 - skyfoot
@AnthonyWJones:当这种事情发生时,总是令人惊喜的 :) - Reed Copsey
@skyfoot:没错,但通常情况下,您会想要一个方法来调用多个方法以指定执行顺序。我同意-它们应该被重构为小部分,但是为了在属性和方法之间进行选择,方法内发生的全部执行(即使它调用另一个方法,该方法又调用另一个方法等等)也很重要考虑。 - Reed Copsey
3
我想在上面的列表中添加一项,即如果成员需要暴露给数据绑定,则应将其设置为属性。 - Robert Rossney

13

以下是Microsoft的准则:

在属性和方法之间进行选择

  • 如果成员表示类型的逻辑属性,请考虑使用属性。

  • 如果属性的值存储在进程内存中并且属性只提供对该值的访问,请使用属性而不是方法。

  • 在以下情况下请使用方法,而不是属性。

    • 操作比字段集慢数个数量级。如果您正在考虑提供异步操作的版本以避免阻塞线程,则很可能操作过于昂贵,不能作为属性。特别是,访问网络或文件系统(初始化之外)的操作应该是方法,而不是属性。

    • 操作是转换操作,例如Object.ToString方法。

    • 每次调用时返回不同的结果,即使参数未更改。例如,NewGuid方法每次调用时返回不同的值。

    • 操作具有重大且可观察的副作用。请注意,填充内部缓存通常不被视为可观察的副作用。

    • 操作返回内部状态的副本(这不包括在堆栈上返回的值类型对象的副本)。

    • 操作返回数组。


5

当语义是“从对象中获取某个值”时,我使用属性。然而,使用方法是传达“这可能需要比平凡的努力更多”的好方法。

例如,一个集合可以有一个Count属性。合理地假设集合对象知道当前持有多少项,而无需实际循环遍历并计数它们。

另一方面,这个假想的集合可以有一个GetSum()方法,返回所持项目的总和。集合同样可以有一个Sum属性,但使用方法传达了这样一个观念:集合将不得不付出一些真正的工作来得到答案。


2

如果我会影响到多个字段,我永远不会使用属性 - 我总是会使用方法。

通常,我只使用 public string ErrorLog { get; private set; } 语法来定义属性,并对其他所有内容使用方法。


2

除了Reed的答案之外,当属性只是像获取资源(例如事件日志)这样的getter时,我会尽量仅在属性不会产生副作用时使用属性。


2
如果在一个属性中发生的事情不仅仅是一些琐碎的事情,那么它应该成为一个方法。例如,如果您的ErrorLog getter属性实际上正在读取文件,那么它应该成为一个方法。访问属性应该很快,如果它正在进行大量处理,则应该成为一个方法。如果访问属性会产生用户可能意料不到的副作用,那么它可能应该成为一个方法。
有一本名为 .NET Framework Design Guidelines 的书详细介绍了这种情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接