您应该检查构造函数中的参数值是否错误?

发布于 2024-07-16 10:04:08 字数 54 浏览 9 评论 0原文

您是否在每个构造函数中检查数据有效性,还是只是假设数据正确并在参数有问题的特定函数中抛出异常?

Do you check for data validity in every constructor, or do you just assume the data is correct and throw exceptions in the specific function that has a problem with the parameter?

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

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

发布评论

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

评论(9

忆梦 2024-07-23 10:04:09

我同意一般情况下的 Sharptooth,但有时有些对象可能具有某些功能有效而某些功能无效的状态。 在这些情况下,最好推迟检查具有这些特定依赖项的函数。

通常您需要在构造函数中进行验证,因为这意味着您的对象将始终处于有效状态。 但某些类型的对象需要特定于功能的检查,这也没关系。

I agree with sharptooth in the general case, but there are sometimes objects that can have states in which some functions are valid and some are not. In these situations it's better to defer checks to the functions with these particular dependencies.

Usually you'll want to validate in a constructor, if only because that means your objects will always be in a valid state. But some kinds of objects need function-specific checks, and that's OK too.

冷月断魂刀 2024-07-23 10:04:09

这是一个很难的问题。 在过去的几年里,我多次改变了与这个问题相关的习惯,所以我想到了一些想法:

  • 检查构造函数中的参数就像检查传统方法的参数一样......所以我不会在这里区分...
  • 检查方法的参数当然有助于确保传递的参数正确,但也引入了您必须编写的更多代码,在我看来,这并不总是有回报...特别是当您编写简短的代码时经常委托给其他方法的方法,我猜你最终会得到 50% 的代码只是做参数检查...
  • 此外,考虑到当你为你的类编写单元测试时,你不希望有为所有方法传递有效参数...通常只传递对当前测试用例重要的参数是有意义的,因此进行检查会减慢您编写单元测试的速度...

我认为这实际上取决于情况...我最终的结果是仅当我知道参数确实来自外部系统(例如用户输入、数据库、Web 服务或类似的东西...)时才编写参数检查。 如果数据来自我自己的系统,我大多数时候不会编写测试。

This is a difficult question. I have changed my habit related to this question several times in the last years, so here are some thoughts coming to my mind :

  • Checking the arguments in the constructor is like checking the arguments for a traditional method... so I would not differentiate here...
  • Checking the arguments of a method of course does help to ensure parameters passed are correct, but also introduces a lot of more code you have to write, which not always pays off in my opinion... Especially when you do write short methods which delegate quite frequently to other methods, I guess you would end up with 50 % of your code just doing parameter checks...
  • Furthermore consider that very often when you write a unit test for your class, you don't want to have to pass in valid parameters for all methods... Quite often it does make sense to only pass those parameters important for the current test case, so having checks would slow you down in writing unit tests...

I think this really depends on the situation... what I ended up is to only write parameter checks when I know that the parameters do come from an external system (like user input, databases, web services, or something like that...). If data comes from my own system, I don't write tests most of the time.

烟雨凡馨 2024-07-23 10:04:09

我总是尝试尽早失败。 所以我最终检查了构造函数中的参数。

I always try to fail as early as possible. So I definitively check the parameters in the constructor.

〆一缕阳光ご 2024-07-23 10:04:09

理论上,在调用函数之前,调用代码应始终确保满足先决条件。 构造函数也是如此。

在实践中,程序员很懒,为了确保最好还是检查前提条件。 断言在那里派上用场。

例子。 请原谅我的非大括号语法:

// precondition b<>0
function divide(a,b:double):double;
begin
  assert(b<>0); // in case of a programming error. 
  result := a / b;
end;

// calling code should be:
if foo<>0 then
  bar := divide(1,0)
else
  // do whatever you need to do when foo equals 0

或者,您可以随时更改前提条件。 对于构造函数来说,这并不是很方便。

// no preconditions.. still need to check the result
function divide(a,b:double; out hasResult:boolean):double;
begin
  hasResult := b<>0; 
  if not hasResult then
    Exit;
  result := a / b;
end;

// calling code:
bar := divide(1,0,result);
if not result then
  // do whatever you need to do when the division failed

In theory, the calling code should always ensure that preconditions are met, before calling a function. The same goes for constructors.

In practice, programmers are lazy, and to be sure it's best to still check preconditions. Asserts come in handy there.

Example. Excuse my non-curly brace syntax:

// precondition b<>0
function divide(a,b:double):double;
begin
  assert(b<>0); // in case of a programming error. 
  result := a / b;
end;

// calling code should be:
if foo<>0 then
  bar := divide(1,0)
else
  // do whatever you need to do when foo equals 0

Alternatively, you can always change the preconditions. In case of a constructor this is not really handy.

// no preconditions.. still need to check the result
function divide(a,b:double; out hasResult:boolean):double;
begin
  hasResult := b<>0; 
  if not hasResult then
    Exit;
  result := a / b;
end;

// calling code:
bar := divide(1,0,result);
if not result then
  // do whatever you need to do when the division failed
ι不睡觉的鱼゛ 2024-07-23 10:04:09

总是尽快失败。 运行时展示了这种实践的一个很好的例子..
* 如果您尝试对数组使用无效索引,则会出现异常。
* 尝试铸造时会立即失败,而不是在稍后的某个阶段。

想象一下,如果引用中保留了错误的转换,并且每次您尝试使用它时都会遇到异常,那将是一场灾难代码。 唯一明智的方法是尽快失败并尝试尽快避免不良/无效状态。

Always fail as soon as possible. A good example of this practice is exhibited by the runtime ..
* if you try and use an invalid index for an array you get an exception.
* casting fails immediately when attempted not at some later stage.

Imagine what a disaster code be if a bad cast remained in a reference and everytime you tried to use that you got an exception. The only sensible approach is to fail as soon as possible and try and avoid bad / invalid state asap.

九命猫 2024-07-23 10:04:08

构造函数也是一个函数 - 为什么要区分?

创建对象意味着所有完整性检查都已完成。 检查构造函数中的参数并在检测到非法值后抛出异常是完全合理的。

其中,这简化了调试。 当您的程序在构造函数中引发异常时,您可以观察堆栈跟踪,并且通常可以立即找到原因。 如果您延迟检查,则必须进行更多调查以检测哪些早期事件导致当前错误。

A constructor is a function too - why differentiate?

Creating an object implies that all the integrity checks have been done. It's perfectly reasonable to check parameters in a constructor and throw an exception once an illegal value has been detected.

Among all this simplifies debugging. When your program throws exception in a constructor you can observe a stack trace and often immediately see the cause. If you delay the check you'll then have to do more investigation to detect what earlier event causes the current error.

擦肩而过的背影 2024-07-23 10:04:08

拥有一个完全构造的对象,并且从一开始就“满足”所有不变量总是更好。 但是,请注意非托管语言中的构造函数抛出异常,因为这可能会导致内存泄漏。

It's always better to have a fully-constructed object with all the invariants "satisfied" from the very beginning. Beware, however, of throwing exceptions from constructor in non-managed languages since that may result in a memory leak.

终弃我 2024-07-23 10:04:08

我总是在构造函数中强制值。 如果用户懒得遵守规则,我只是默默地执行它们而不告诉他们。

因此,如果他们传递的值为 107%,我会将其设置为 100%。 我只是在文档中明确说明这就是发生的情况。

只有当没有明显的逻辑强制时,我才会向他们抛出异常。 我喜欢称其为“那些懒惰或愚蠢而无法阅读文档的人最惊讶的原则”。

I always coerce values in constructors. If the users can't be bothered to follow the rules, I just silently enforce them without telling them.

So, if they pass a value of 107%, I'll set it to 100%. I just make it clear in the documentation that that's what happens.

Only if there's no obvious logical coercion do I throw an exception back to them. I like to call this the "principal of most astonishment to those too lazy or stupid to read the documentation".

我喜欢麦丽素 2024-07-23 10:04:08

如果您放入构造函数,堆栈跟踪更有可能显示错误值的来源。

If you throw in the constructor, the stack trace is more likely to show where the wrong values are coming from.

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