要使用只读属性还是方法?


72

我需要公开类实例的“已映射? ”状态。结果通过基本检查确定。它不是简单地暴露字段的值。我不确定应该使用只读属性还是方法。

只读属性:

public bool IsMapped
{
    get
    {
        return MappedField != null;
    }
}

方法:

public bool IsMapped()
{
    return MappedField != null;
}

我已经阅读了MSDN的“属性和方法之间选择”,但仍不确定。


1
我认为sysexpands在James的答案中的注释就是您的答案。当您回顾您的代码或其他开发人员时,会看到它;将其作为属性几乎可以肯定地表明,它仅返回与字段相关的值。没有理智的开发人员会将过多的功能放入财产权中吗?另一方面,有10个答案都说RO属性肯定是相同的答案

2
那么阅读MappedField意味着什么呢?它是对变量的简单读取,还是潜在的昂贵操作或具有副作用(例如延迟加载)的操作?
用户

Answers:


88

C#标准说

第8.7.4节

属性是提供访问对象或类的特性的部件。属性的示例包括字符串的长度,字体的大小,窗口的标题,客户的名称等。属性是字段的自然扩展。两者都是具有关联类型的命名成员,并且访问字段和属性的语法相同。但是,与字段不同,属性不表示存储位置。相反,属性具有访问器,这些访问器指定在读取或写入其值时要执行的语句。

而方法定义为

第8.7.3节

方法是一种部件,其实现可以由对象或类执行的计算或操作。方法具有形式参数的列表(可能为空),返回值(除非方法的return-type为void),并且为静态或非静态。

使用属性方法来实现封装。属性封装数据,方法封装逻辑。因此,如果要公开数据,则应首选只读属性。在您的情况下,没有逻辑可以修改对象的内部状态。您想提供对对象特征的访问

对象的实例是否是对象IsMapped的特征。它包含一个检查,但这就是为什么您有属性可以访问它。可以使用逻辑定义属性,但不应公开逻辑。就像第一个引号中提到的示例一样:想象一下该String.Length属性。根据实现的不同,此属性可能会遍历字符串并计算字符。它也确实执行操作,但是“从外部”仅给出对象的内部状态/特性的声明。


4
您想提供对对象特征的访问。 ”-这是我一直在寻找的东西。这是使用适当的MSDN参考的最完整答案。谢谢。
Dave New

3
虽然这不是一个严格的规则,但是当返回属性的计算时间非常重要时,我倾向于使用一种方法。属性应立即返回。
安德鲁·汉隆

3
+1可清楚地关注语义而不是形式标准
Vlad

22

我会使用该属性,因为没有真正的“做”(动作),没有副作用,并且也不太复杂。


1
我希望编码人员尽可能多地这样说:“我不使用***,因为没有参数,我为什么要这么做”。
Nakilon


7

我去买房。主要是因为所引用的MSDN文章的第一句:

通常,方法代表动作,属性代表数据。


4

在这种情况下,我似乎很清楚应该将其作为财产。这是一个简单的检查,没有逻辑,没有副作用,没有性能影响。没有比检查更简单的了。

编辑:

请注意,如果出现任何上述的,你会把它变成一个方法,该方法应该包括一个强有力的动词,不是助动词像是或有。一种方法可以执行某些操作。您可以将其命名为VerifyMapping或DefineMappingExistance或其他名称,只要它以动词开头即可。


但是MappedField != null根据定义,这是一种逻辑陈述。
Dave New

您在这里假设阅读MappedField是简单,快速且没有副作用的。我们不知道那是真的。
用户

4
@MichaelKjörling显然,他本可以实现一个自定义运算符!=来格式化硬盘,但是您可以用很多方法破坏所有东西。只要未指定任何内容,我将假定我所看到的符合标准。
nvoigt

4

我认为您链接中的这一行就是答案

方法代表动作,属性代表数据。

这里没有任何动作,只有一条数据。所以这是一个财产。


3
它确实很重要...(一个动作)
Lotok

2
但是我也在做一个动作...null检查
Dave New

1
您正在检查一条数据,而不是对其执行任何操作。-如果根据结果执行其他操作或执行计算或其他操作,则将是一种方法。
Lotok

9
IEnumerable.Count()是一种扩展方法,它基本上遍历集合并计数包含元素。另一方面,IList.Count是一个属性,因为它不遍历列表-列表已经知道其计数,只是从该属性返回它。
Zoran Horvat

5
IEnumerable.Count()不存在。Count()是一种扩展方法,可在静态类Enumerable中找到,并且1)扩展属性不存在,以及2)Count()可能很耗时(尤其是在复杂的LINQ查询中)。
Dave Van den Eynde

3

如果在任何时候都需要添加参数以获得值,那么就需要一个方法。否则你需要一个属性


3
有了这个定义,索引属性又如何呢?
2013年

如果该值在对象中占主要部分,那么可以。
奥德斯

3

在可以访问这两种构造的情况/语言中,一般的划分如下:

  • 如果请求是针对对象具有的东西,请使用属性(或字段)。
  • 如果请求是对象执行某操作的结果,请使用方法。

更具体地说,属性将用于以读取和/或写入方式访问(出于消费目的)由暴露该属性的对象拥有的数据成员。属性比字段更好,因为数据不必一直以持久形式存在(它们使您对数据值的计算或检索变得“懒惰”),并且它们比为此目的的方法更好。您仍然可以在代码中使用它们,就像它们是公共字段一样。

但是,属性不应导致副作用(可能的,可以理解的例外情况是,设置变量以保留返回的值,从而避免了多次昂贵的值的重新计算);在所有其他条件相同的情况下,它们应该返回确定性结果(因此NextRandomNumber是属性的错误概念选择),并且计算不应导致会影响其他计算的任何状态数据发生更改(例如,获取PropertyA和按此顺序排列的PropertyB不应返回与先获取PropertyB然后再获取PropertyA相同的结果。

OTOH方法在概念上被理解为执行某些操作并返回结果。简而言之,它会执行某些操作,可能会超出计算返回值的范围。因此,当返回值的操作具有其他副作用时,将使用方法。返回值可能仍然是某些计算的结果,但是该方法可能已经不确定地计算了该值(GetNextRandomNumber()),或者返回的数据采用对象的唯一实例的形式,再次调用该方法会产生一个不同的实例,即使它可能具有相同的数据(GetCurrentStatus()),或者该方法可能更改状态数据,使得连续两次执行完全相同的操作也会产生不同的结果(EncryptDataBlock();


2

恕我直言,第一个只读属性是正确的,因为IsMapped作为对象的属性,并且您没有执行任何操作(仅是评估),但是最终,与现有代码库的一致性可能会超出语义...。除非这是一个单任务


2

我会同意这里的人的说法,因为它正在获取数据,并且没有副作用,所以它应该是一种财产。

进一步说,如果某人“从外面看”它的意义,我也会接受setter(而不是getter)的一些副作用。

一种考虑方法是方法是动词,属性是形容词(同时,对象本身是名词,而静态对象是抽象名词)。

动词/形容词准则的唯一例外是,在获取(或设置)所讨论的信息时,使用方法而不是属性可能是很有意义的:在逻辑上,此类功能可能仍应是属性,但是人们习惯将性能视为对性能的影响不大,尽管没有真正的理由为什么总是如此,但强调一下这一点可能会很有用 GetIsMapped()相对较重的性能。

在运行代码的级别上,调用属性和调用等效方法来获取或设置绝对没有区别。所有这些都是为了使使用该代码的人的生活更加轻松。


1

我期望属性,因为它仅返回字段的详细信息。另一方面,我期望

MappedFields[] mf;
public bool IsMapped()
{
     mf.All(x => x != null);
}

在此示例中,您将执行多项null检查。这在逻辑上与我也在执行null检查的我有什么不同?
Dave New

它的不同之处在于您不询问MF的每个成员,否则您不知道答案
2013年

0

您应该使用该属性,因为c#具有此属性

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.