属性与方法
快速的问题:你什么时候决定使用属性(在C#中)以及什么时候决定使用方法?
我们正忙着进行这个辩论,并且发现有些地方是否应该使用财产或方法是值得商榷的。 其中一个例子是:
public void SetLabel(string text) { Label.Text = text; }
在这个例子中, Label
是一个ASPX页面上的控件。 是否有一个原则可以决定(在这种情况下)是否使这个方法或财产的决定。
我会接受最全面和最全面的答案,但这也触及了我所给出的例子。
从“开发类库的设计指南”的“ 属性和方法之间的选择”部分:
通常,方法表示动作和属性表示数据。 属性意味着像字段一样使用,这意味着属性不应该在计算上复杂或产生副作用。 如果不违反以下准则,请考虑使用属性而不是方法,因为经验较少的开发人员会发现属性更易于使用。
是的,如果你正在做的是获得和设置,使用一个属性。
如果你正在做一些复杂的事情,可能会影响到一些数据成员,一种方法是更合适的。 或者如果你的getter使用参数,或者你的setter的参数不止一个值。
中间是灰色区域,线条可能有点模糊。 没有硬性规定,不同的人有时会不同意某种东西是财产还是方法。 重要的是要做到(相对)与你如何做(或你的团队如何做)相一致。
它们在很大程度上是可以互换的,但是一个属性告诉用户实现相对“简单”。 哦,语法是一点点清洁。
一般来说,我的理念是,如果你开始写一个以get或set开头的方法名,并分别取零或一个参数,那么它是一个属性的主要候选者。
如果你正在设置你的对象的实际属性,那么你使用一个属性。
如果你正在执行任务/功能,那么你使用一种方法。
在你的例子中,这是一个确定的属性被设置。
但是,如果你的功能是AppendToLabel,那么你会使用一个方法。
属性是一种从对象注入或检索数据的方法。 它们创建一个对类中的变量或数据的抽象。 它们类似于Java中的getter和setter。
方法封装一个操作。
一般来说,我使用属性来公开单个数据位,或者像一个类销售税一样小的计算。 这是从购物车中的物品数量和成本中得出的。
我在创建操作时使用方法,如从数据库中检索数据。 任何具有移动部件的操作都是方法的候选。
在你的代码示例中,如果需要在包含类的外部访问它,我会将其包装在一个属性中:
public Label Title { get{ return titleLabel;} set{ titleLabel = value;} }
设置文本:
Title.Text = "Properties vs Methods";
如果我只是设置标签的文本属性,这是我将如何做到这一点:
public string Title { get{ return titleLabel.Text;} set{ titleLabel.Text = value;} }
设置文本:
Title = "Properties vs Methods";
你只需要看看这个名字…“财产”。 这是什么意思? 字典在很多方面对它进行了定义,但在这种情况下,“一个事物的本质或特征属性或质量”最适合。
想想行动的目的。 事实上,你是在改变还是在检索“一个本质的或独特的属性”? 在你的例子中,你正在使用一个函数来设置一个文本框的属性。 这似乎有点傻,不是吗?
属性真的是功能。 他们都编译得到XXX()和setXXX()。 它只是将它们隐藏在句法糖中,但它为过程提供了语义意义的糖。
考虑属性等属性。 一辆汽车有很多属性。 颜色,手摇,模型等。并不是所有的属性都是可封闭的,有些是可以计算的。
同时,一个方法是一个行动。 GetColor应该是一个属性。 GetFile()应该是一个函数。 另一个经验法则是,如果它不改变对象的状态,那么它应该是一个函数。 例如,CalculatePiToNthDigit(n)应该是一个函数,因为它实际上并不改变它所连接的Math对象的状态。
这可能是漫不经心的,但它确实归结为决定你的对象是什么,他们代表什么。 如果你不能确定它应该是一个财产或功能,也许这是没有关系。
语义属性是对象的属性。 方法是你的对象的行为。
标签是一个属性,使它成为一个属性更有意义。
在面向对象编程方面,您应该清楚地了解什么是行为的一部分,什么是一个属性。
汽车{颜色,型号,品牌}
一辆车具有颜色,型号和品牌属性,因此具有方法SetColor或SetModel是没有意义的,因为在语义上我们不要求Car设置自己的颜色。
所以如果你将属性/方法的情况映射到现实生活中的对象或者从语义的角度来看它,你的困惑就会消失。
通过MSDN搜索,我找到了一个关于Properties vs Methods的参考,它为创建方法提供了一些很好的指导:
- 该操作是一个转换,如
Object.ToString
。- 该操作非常昂贵,您想要与用户沟通,他们应该考虑缓存结果。
- 使用get访问器获取属性值会产生可观察的副作用。
- 连续两次调用成员会产生不同的结果。
- 执行顺序很重要。 请注意,类型的属性应该能够以任何顺序进行设置和检索。
- 该成员是静态的,但返回一个可以更改的值。
- 该成员返回一个数组。 返回数组的属性可能是非常具有误导性的。 通常有必要返回内部数组的副本,以便用户不能更改内部状态。 这加上用户可以轻易认定它是索引属性的事实导致代码效率低下。
我更喜欢使用1个参数的add / set方法的属性。 如果参数更多,请使用方法。
属性应该只是简单的设置,并得到一个衬里。 任何更多的东西,它应该真的被转移到一种方法。 复杂的代码应该总是在方法中。
我只使用变量访问的属性,即获取和设置单个变量,或获取和设置控件中的数据。 一旦需要/执行任何类型的数据操作,我就使用方法。
对于Properties来说还有一个很大的好处,那就是在调试过程中可以在Visual Studio中看到属性的值。
属性是非常好的,因为它们可以在Visual Studio的可视化设计器中访问,只要它们可以访问。
如果你只是设置和获取,也许一些验证不会访问大量的代码,那么它们会被使用。 要小心,因为在验证过程中创建复杂的对象并不简单。
其他方法是首选的方法。
这不只是关于语义。 在视觉工作室的视觉设计师中使用不合适的属性开始出现怪异现象。
例如,我正在获得一个类的属性中的配置值。 配置类实际上会打开一个文件并运行一个sql查询来获取该配置的值。 这导致了我的应用程序中的配置文件将被Visual Studio本身而不是我的应用程序打开和锁定的问题,因为不仅是读取,而且写入配置值(通过setter方法)。 为了解决这个问题,我只好把它改成一个方法。
作为设计问题属性表示类对象的数据或属性,而方法是类对象的动作或行为。
在.Net中,世界还有其他一些使用属性的含义:
- 数据绑定使用属性,而get_ / set_方法则不使用。
- XML序列化用户属性作为自然的服务机制。
- 属性由PropertyGrid控件和ICustomTypeDescriptor实例访问,如果您正在编写自定义库,可以使用该属性 。
- 属性由属性控制,人们可以明智地使用它来设计面向方面的软件。
误解(恕我直言)关于属性的用法:
- 用于公开小计算: ControlDesigner.SelectionRules的get块运行到72行!
- 用于公开内部数据结构:即使某个属性没有映射到内部数据成员,也可以将其用作属性,如果该属性是类的属性的话。 Viceversa,即使它的类属性是不可取的,也要返回像数据成员一样的数组(而不是方法用于返回成员的深层副本)。
在这个例子中,它可以被写成,具有更多的商业意义:
public String Title { set { Label.Text = text; } }
我来自一个我使用得到..设置..一段时间的方法。
当我写代码时,我不会问自己:“访问这些数据很简单,还是需要一个繁重的过程?” 因为事情可以改变 (今天回顾这个属性很简单,tomonrow可能需要一些或繁重的过程)。
今天我有一个方法SetAge(int age)tomonrow我也将有方法SetAge(日期出生日期)计算年龄使用出生日期。
我感到非常失望的是编译器在get和set中转换属性,但不认为我的Get …和Set ..方法是一样的。
比尔·瓦格纳 ( Bill Wagner)提供了一些关于什么时候使用属性和方法的指导方针
- 当所有这些都是真的时候使用属性:getters应该是简单的,因此不太可能抛出异常。 请注意,这意味着没有网络(或数据库)访问。 要么可能会失败,因此会抛出异常。
- 他们不应该有彼此依赖。 请注意,这将包括设置一个属性,并影响另一个属性。 (例如,设置FirstName属性会影响只读的FullName属性,该属性包含名字+姓氏属性意味着这种依赖关系)
- 它们应该以任何顺序设置
- 吸气剂没有明显的副作用注意这个指导方针并不排除一些属性的惰性评估形式。
- 该方法必须总是立即返回。 (请注意,这排除了进行数据库访问调用,Web服务调用或其他类似操作的属性)。
- 如果成员返回一个数组,则使用方法。
- 重复调用getter(不插入代码)应返回相同的值。
-
对二传手的重复呼叫(具有相同的值)应该不会影响单个呼叫。
-
get不应该返回对内部数据结构的引用(请参阅第23项)。 一个方法可以返回一个深层的副本,并可以避免这个问题。
*从我的答案采取重复的问题。