Getters和Setters应该和不应该做什么

时间:2010-05-25 20:47:43

标签: properties setter getter

  

可能重复:
  Convention question: When do you use a Getter/Setter function rather than using a Property

我最近对Getters and Setters遇到了很多不同的意见,所以我想我应该把它变成自己的问题。

我的previous question收到了立即评论(后来被删除),声明的setter不应该有任何副作用,而SetProperty方法将是更好的选择。

实际上,这似乎也是Microsoft's opinion。但是,当设置表单的ResizedWidth属性时,它们的属性通常会引发事件,例如HeightOwenP还声明“你不应该让一个属性抛出异常,属性不应该有副作用,顺序不应该重要,属性应该相对快速地返回。”

然而Michael Stum指出在验证setter中的数据时应该抛出异常。如果您的setter没有抛出异常,那么您如何有效地验证数据,因为this question的许多答案都表明了这一点?

当你需要举办活动时,几乎所有微软的Control都会这样做?那么你是不是受到任何订阅你的活动的怜悯?如果他们的处理程序执行大量信息,或者自己抛出错误,那么你的setter会发生什么?

最后,getter中的lazy loading怎么样?这也可能违反了之前的指导原则。

放置在getter或setter中可以接受什么,以及只应在accessor方法中保留什么?

修改

来自MSDN中的另一个article

  

getset方法通常与其他方法没有区别。它们可以执行任何程序逻辑,抛出异常,被覆盖,并使用编程语言允许的任何修饰符进行声明。但请注意,属性也可以是静态的。如果属性是静态的,则getset方法可以执行的操作存在限制。有关详细信息,请参阅编程语言参考。

3 个答案:

答案 0 :(得分:16)

我的观点:

  1. 如果预期定位器或吸气剂价格昂贵,请不要将其作为属性,将其作为方法。

  2. 如果设置属性会因更改而触发事件,则可以。你怎么能让听众收到变化通知?但是,您可能希望提供BeginInit / EndInit对来抑制事件,直到进行所有更改。通常情况下,事件处理程序有责任立即返回,但如果您真的不相信它,那么您可能希望在另一个线程中发出该事件的信号。

  3. 如果设置属性会抛出无效值的异常,那也没关系。当值完全错误时,这是​​发出问题的合理方式。在其他情况下,您设置一组属性,然后调用使用它们执行某些操作的方法,例如建立连接。这将允许在使用属性之前保持验证和错误处理,因此属性不需要抛出任何东西。

  4. 访问某个属性可能会产生副作用,只要它们不是意料之外的并不重要。这意味着getter中的JIT实例化很好。同样,每当进行更改时为实例设置脏标志就好了,因为它设置了相关属性,例如相同值的不同格式。

  5. 如果做某事而不是仅仅访问一个值,它应该是一个方法。方法是动词,因此创建连接将由OpenConnection()方法完成,而不是Connection属性。 Connection属性将用于检索正在使用的连接,或将实例绑定到另一个连接。

  6. 编辑 - 添加5,更改2和3

答案 1 :(得分:1)

我同意getter / settings不应该有副作用的想法,但我会说它们不应该有非明显的副作用。

就抛出异常而言,如果要将属性设置为无效值(在非常基本的意义上),那么验证异常就可以了。但是,如果setter正在运行一系列复杂的业务规则验证,或试图关闭并更新其他对象或任何其他可能导致异常的事情,那么这很糟糕。但是这个问题并不是异常本身的问题,而是设置器正在关闭并秘密执行调用者不会(或不应该)期望的大量功能。

与事件相同。如果一个setter正在抛出一个事件,说“这个属性改变了”,那就没关系,因为这是一个明显的副作用。但是,如果它触发了一些其他自定义事件,导致一些隐藏的代码块在系统的另一部分执行,那就太糟糕了。

这与我在getter中避免延迟加载的原因相同。实际上,它们可以在很多时候使事情变得更容易,但是它们可以在某些时候使事情变得更加混乱,因为在你想要加载子对象的时候总是会出现错综复杂的逻辑。在填充父对象时,通常只需要再添加一行代码来显式加载子对象,这样可以避免对对象状态造成很多混淆。但是这方面可能会非常主观,而且很多都取决于具体情况。

答案 2 :(得分:0)

无论如何,我总是发现保守的方法是最好的。因为属性在语法上与字段相同,所以它们应该像字段一样工作:没有例外,没有验证,没有有趣的业务。 (实际上,我的大多数属性都是以简单的字段开头,并且在绝对必要之前不会成为属性。)这个想法是,如果你看到的东西看起来像是在设置或设置字段集,那么它就像是获取或者在功能方面设置一个字段(没有抛出异常),整体效率(例如,设置变量不会触发委托调用的级联)和对程序状态的影响(设置变量设置该变量,并且不会打电话给很多可以做任何事情的代表。

设置属性的明智之处包括设置一个标志以指示存在更改:

set {
    if(this.value!=value) {
        this.changed=true;
        this.value=value;
    }
}

也许实际上在另一个对象上设置了一个值,例如:

set { this.otherObject.value=value; }

可能会稍微解开输入,以简化类的内部代码:

set {
    this.isValid=(value&Flags.IsValid)!=0;
    this.setting=value&Flags.SettingMask;
}

(当然,在后两种情况下,get函数可能正好相反。)

如果需要发生任何更复杂的事情,特别是调用代理,执行验证或抛出异常,那么我认为函数更好。 (通常,我的字段变为带有get和set的属性,然后最终成为get属性和set函数。)同样对于getter;如果你要返回对某事物的引用,那就没问题了,但是如果你正在创建一个全新的大对象并在每次读取属性时填充它 - 不是那么热。