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

发布于 2024-09-03 03:09:29 字数 1859 浏览 4 评论 0原文

可能的重复:
约定问题:何时你使用 Getter/Setter 函数而不是使用 Property

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

我的我之前的问题立即收到了评论(后来删除)指出 setter 不应该有任何副作用,并且 SetProperty 方法将是更好的选择。

事实上,这似乎是微软的观点 也是如此。但是,它们的属性通常会引发事件,例如设置表单的 WidthHeight 属性时的 Resized 事件。 OwenP 还指出“你不应该让属性抛出异常,属性不应该有副作用,顺序不重要,并且属性应该相对较快地返回。”

然而 Michael Stum 指出应该抛出异常在设置器中验证数据。如果您的设置器不抛出异常,那么您如何有效地验证数据,正如

当您需要像几乎所有 Microsoft Control 一样发起事件时该怎么办?那么您不是受到订阅您活动的人的摆布吗?如果他们的处理程序执行大量信息,或者本身抛出错误,那么您的设置程序会发生什么?

最后,getter 中的延迟加载怎么样?这也可能违反之前的指导方针。

什么可以放在 getter 或 setter 中,什么应该只保留在访问器方法中?

编辑:

来自另一个文章

getset 方法通常与其他方法没有什么不同。它们可以执行任何程序逻辑、引发异常、被覆盖以及使用编程语言允许的任何修饰符进行声明。但请注意,属性也可以是静态的。如果属性是静态的,则 getset 方法的功能会受到限制。有关详细信息,请参阅您的编程语言参考。

Possible Duplicate:
Convention question: When do you use a Getter/Setter function rather than using a Property

I've run into a lot of differing opinions on Getters and Setters lately, so I figured I should make it into it's own question.

A previous question of mine received an immediate comment (later deleted) that stated setters shouldn't have any side effects, and a SetProperty method would be a better choice.

Indeed, this seems to be Microsoft's opinion as well. However, their properties often raise events, such as Resized when a form's Width or Height property is set. OwenP also states "you shouldn't let a property throw exceptions, properties shouldn't have side effects, order shouldn't matter, and properties should return relatively quickly."

Yet Michael Stum states that exceptions should be thrown while validating data within a setter. If your setter doesn't throw an exception, how could you effectively validate data, as so many of the answers to this question suggest?

What about when you need to raise an event, like nearly all of Microsoft's Control's do? Aren't you then at the mercy of whomever subscribed to your event? If their handler performs a massive amount of information, or throws an error itself, what happens to your setter?

Finally, what about lazy loading within the getter? This too could violate the previous guidelines.

What is acceptable to place in a getter or setter, and what should be kept in only accessor methods?

Edit:

From another article in the MSDN:

The get and set methods are generally no different from other methods. They can perform any program logic, throw exceptions, be overridden, and be declared with any modifiers allowed by the programming language. Note, however, that properties can also be static. If a property is static, there are limitations on what the get and set methods can do. See your programming language reference for details.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

失与倦" 2024-09-10 03:09:29

我的观点:

  1. 如果 setter 或 getter 预计会很昂贵,请不要将其设为属性,而应将其设为方法。

  2. 如果设置属性会因更改而触发事件,这很好。您还能如何让听众收到更改通知?但是,您可能希望提供 BeginInit/EndInit 对来抑制事件,直到完成所有更改。通常,事件处理程序有责任及时返回,但如果您确实不能相信它会这样做,那么您可能希望在另一个线程中向该事件发出信号。

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

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

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

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

My view:

  1. If a setter or getter is expected to be expensive, don't make it a property, make it a method.

  2. If setting a property triggers events due to changes, this is fine. How else would you allow listeners to be notified of changes? However, you may want to offer a BeginInit/EndInit pair to suppress events until all changes are made. Normally, it is the responsibility of the event handler to return promptly, but if you really can't trust it to do so, then you may wish to signal the event in another thread.

  3. If setting a property throws exceptions on invalid values, it's also fine. This is a reasonable way to signal the problem when the value is completely wrong. In other cases, you set a bunch of properties and then call a method that uses them to do something, such as make a connection. This would allow holding off validation and error-handling until the properties are used, so the properties would not need to throw anything.

  4. Accessing a property may have side-effects so long as they aren't unexpected and don't matter. This means a JIT instantiation in a getter is fine. Likewise, setting a dirty flag for the instance whenever a change is made is just fine, as it setting a related property, such as a different format for the same value.

  5. If it does something as opposed to just accessing a value, it should be a method. Method are verbs, so creating a connection would be done by the OpenConnection() method, not a Connection property. A Connection property would be used to retrieve the connection in use, or to bind the instance to another connection.

edit - added 5, changed 2 and 3

入怼 2024-09-10 03:09:29

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

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

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

这与我避免在吸气剂中延迟加载的原因相同。事实上,它们在很多时候可以让事情变得更容易,但有时它们也可以让事情变得更加混乱,因为在您想要加载子对象的确切时间周围总是会出现令人费解的逻辑。当您填充父对象时,通常只需多一行代码即可显式加载子对象,并且可以避免对对象状态的很多混淆。但这方面可能会变得非常主观,很大程度上取决于具体情况。

I agree with the idea that getters/settings shouldn't have side effects, but I would say that they shouldn't have non-obvious side effects.

As far as throwing exceptions, if you are setting a property to an invalid value (in a very basic sense), then validation exceptions are fine. However, if the setter is running whole series of complicated business rule validation, or trying to go off and update other objects, or any other thing that may cause an exception, then that is bad. But this problem is not really an issue with the exception itself, but rather that the setter is going off and secretly performing a lot of functionlity that the caller would not (or should not) expect.

The same with events. If a setter is throwing an event saying that "this property changed", then it's OK, because that's an obvious side effect. But if it's firing off some other custom event so cause some hidden chuck of code to execute in another part of a system, it's bad.

This is the same reason that I avoid lazy-loading in getters. Indeed, they can make things easier a lot of the time, but they can make things a more confusing some of the time, because there always ends up being convoluted logic around exactly when you want the child objects loaded. It's usually just one more line of code to explicitly load the child objects when you are populating the parent object, and it can avoid a lot of confusion about the object state. But this aspect can get very subjective, and a lot of it depends on the situation.

ぇ气 2024-09-10 03:09:29

无论如何,在使用 C# 工作时,我始终发现保守方法是最好的。因为属性在语法上与字段相同,所以它们应该像字段一样工作:没有例外,没有验证,没有有趣的事情。 (事实上​​,我的大多数属性都是从简单字段开始的,除非绝对必要,否则不会成为属性。)这个想法是,如果您看到看起来像是获取或设置字段集的东西,那么它就像获取或设置设置字段,包括功能(不会抛出异常)、整体效率(例如,设置变量不会触发级联委托调用)以及对程序状态的影响(设置变量会设置该变量,并且不会不要召集很多几乎可以做任何事情的代表)。

属性集要做的明智的事情包括设置一个标志来指示发生了更改:

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 也是如此;如果你要返回对某些东西的引用,那没问题,但如果你要创建一个全新的大对象并在每次读取属性时填充它——那就不太热了。

I've always found the conservative approach to be best, when working in C# anyway. Because properties are syntactically the same as fields, they should work like fields: no exceptions, no validation, no funny business. (Indeed, most of my properties start out as simple fields, and don't become properties until absolutely necessary.) The idea is that if you see something that looks like it's getting or setting a field set, then it IS something like getting or setting a field, in terms of functionality (there is no exception thrown), overall efficiency (setting variables doesn't trigger a cascade of delegate calls, for example) and effect on program's state (setting a variable sets that variable, and doesn't call lots of delegates that could do just about anything).

Sensible things for a property set to do include setting a flag to indicate that there's been a change:

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

Perhaps actually set a value on another object, e.g.:

set { this.otherObject.value=value; }

Maybe disentangle the input a bit, to simplify the class's internal code:

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

(Of course, in these latter two cases, the get function might well do the opposite.)

If anything more complicated needs to happen, in particular calling delegates, or performing validation, or throwing exceptions, then my view is that a function is better. (Quite often, my fields turn into properties with get and set, and then end up as a get property and a set function.) Similarly for the getters; if you're returning a reference to something, it's no problem, but if you're creating a whole new large object and filling it in each time the property is read -- not so hot.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文