代码之家  ›  专栏  ›  技术社区  ›  dlras2

getter和setter应该和不应该做什么[复制]

  •  19
  • dlras2  · 技术社区  · 15 年前

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

    最近我在getter和setter上遇到了很多不同的意见,所以我想我应该把它变成自己的问题。

    previous question 我收到了一个即时评论(后来删除),说设置者不应该有任何副作用,以及 SetProperty 方法会是更好的选择。

    事实上,这似乎是 Microsoft's opinion 也。但是,它们的属性经常引发事件,例如 Resized 当窗体的 Width Height 属性已设置。 OwenP 同时声明“你不应该让一个属性抛出异常,属性不应该有副作用,顺序不应该重要,属性应该相对快速地返回。”

    然而 Michael Stum 声明在验证setter中的数据时应引发异常。如果setter没有抛出异常,那么如何有效地验证数据,以及对 this question 建议?

    当你需要引发一个事件时,比如几乎所有微软的控件都需要做什么呢?那么,你不是听任谁赞助了你的活动吗?如果它们的处理程序执行大量信息,或者抛出错误本身,那么您的setter会发生什么?

    最后,怎么样 lazy loading 在吸气剂里?这也可能违反先前的准则。

    在getter或setter中放置什么是可接受的,并且只应在访问器方法中保留什么?

    编辑:

    从另一个 article 在MSDN中:

    这个 get set 方法通常与其他方法没有区别。它们可以执行任何程序逻辑,抛出异常,被重写,并用编程语言允许的任何修饰符声明。但是请注意,属性也可以是静态的。如果属性是静态的,则对 得到 设置 方法可以做到。有关详细信息,请参阅编程语言参考。

    3 回复  |  直到 15 年前
        1
  •  16
  •   Steven Sudit    15 年前

    我的看法是:

    1. 如果一个setter或getter被认为是昂贵的,那么不要将其设置为属性,而是将其设置为方法。

    2. 如果设置属性会由于更改而触发事件,则可以。您还将如何允许侦听器收到更改通知?但是,您可能希望提供BeginInit/EndInit对来抑制事件,直到进行所有更改。通常情况下,事件处理程序负责及时返回,但是如果您真的不能信任它这样做,那么您可能希望在另一个线程中向事件发送信号。

    3. 如果设置属性会对无效值引发异常,也可以。这是一种在值完全错误时发出问题信号的合理方法。在其他情况下,您设置一组属性,然后调用一个方法,使用它们来做一些事情,例如建立连接。这将允许在使用属性之前延迟验证和错误处理,因此属性不需要抛出任何内容。

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

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

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

        2
  •  1
  •   Mike Mooney    15 年前

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

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

    事件也是如此。如果一个setter抛出一个事件说“这个属性改变了”,那么它是可以的,因为这是一个明显的副作用。但是,如果它触发了其他自定义事件,从而导致一些隐藏的代码在系统的另一部分执行,那就不好了。

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

        3
  •  0
  •   please delete me    15 年前

    不管怎么说,在C工作时,我总是认为保守的方法是最好的。因为属性在语法上与字段相同,所以它们应该像字段一样工作:没有异常,没有验证,没有有趣的业务。(实际上,我的大多数属性都是以简单字段开始的,直到绝对必要时才成为属性。)其想法是,如果您看到某个看起来像是正在获取或设置字段集的内容,那么就功能(没有例外)、总体效率(设置VA)而言,它就像获取或设置字段一样。例如,riables不会触发委托调用的级联,也不会影响程序的状态(设置一个变量设置该变量,并且不会调用很多可以做任何事情的委托)。

    对一个属性集来说,明智的做法包括设置一个标志来指示发生了变化:

    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,类似;如果要返回对某个对象的引用,这没问题,但如果要创建一个全新的大对象,并在每次读取该属性时将其填充,则不会太热。