简体   繁体   English

我可以/应该使用异常对程序进行错误检查吗?

[英]Can I/Should I use exceptions to error check my program?

The main example here is copying a word document. 这里的主要示例是复制Word文档。 I have these lines of code in my program: 我的程序中包含以下代码行:

try
{
    File.Copy(docTemplatePath, docOutputPath, true);
}
catch (IOException e)
{
    MessageBox.Show(e.ToString());
}

Now I'm trying to build in error checks. 现在,我正在尝试建立错误检查。 I want to make sure that the output Word Document is not open elsewhere before I try to save, because otherwise an exception is thrown. 我想确保在尝试保存之前未在其他位置打开输出Word文档,因为否则会引发异常。

The way I see it is that the exception is thrown to warn me of an error that is causing the default functionality of the code to not work as expected. 我看到的方式是引发异常,以警告我导致错误的默认功能无法正常工作的代码。 In this sense I would feel comfortable catching an exception, reading it to discern the issue (in this case that the document is currently locked/open elsewhere) and thus showing a MessageBox to alert the user to the fact the document they're trying to write to a file that is open elsewhere. 从这个意义上讲,我会很乐意捕获异常,阅读该异常以识别问题(在这种情况下,该文档当前处于锁定状态/在其他位置打开),因此显示了一个MessageBox来提醒用户要尝试的文档事实写入在其他位置打开的文件。

Is this fine to do? 这样可以吗? I have seen many places over the course of my looking into this where it would seem that this is what exceptions are designed to do, and other places where people seem to think thaat using exception to do stuff like this is hideously against all programming traditions and would prefer to check themselves. 在我研究此过程的过程中,我看到了很多地方,这似乎是异常的设计目标,而其他地方似乎人们认为使用异常来做这样的事情,这与所有编程传统相悖,并且宁愿自己检查一下。

What is the overall consensus? 总体共识是什么?

Thanks 谢谢

You should use Exceptions to handle exceptional occurrences . 您应该使用Exception处理异常情况

That is; 那是; sometimes there will be foreseeable circumstances: A file name entered by a user might not exist, so your code should check File.Exists() before attempting to load it, for example (not relying on an exception). 有时会出现可预见的情况:用户输入的文件名可能不存在,因此,例如,在尝试加载文件之前,您的代码应检查File.Exists() (不依赖于异常)。

That file already being in use and locked by something else might be an exceptional situation; 该文件已经被使用并且被其他东西锁定可能是一种例外情况。 it probably is, so that's probably just fine. 可能是这样,所以可能就好了。

IMO, in .Net, exceptions should be used for managed unexpected errors. 在.Net中,IMO应将异常用于托管的意外错误。

For me it's a bad idea to throw an exception for a authentification error (like bad password) but it's a good to use it for manage a database connection error. 对我来说,抛出一个身份验证错误(例如错误的密码)异常是一个坏主意,但是使用它来管理数据库连接错误则是一个好主意。

So, in few words, i use exceptions in order to manage unexpectable issues and not business issues. 因此,简而言之,我使用异常来管理不可预期的问题而不是业务问题。 The idea of doing every business issues with an exception is more an "over" object oriented approach and is not what it should be use for. 进行所有业务问题的想法都是一种“过度”的面向对象方法,而不是它应用于的目的。

Your example is IMO a good example of the good way to use exception. 您的例子是IMO,这是使用异常的好方法的一个很好的例子。 Globally it's just a "big" try/catch around functionnality or specific tasks. 在全球范围内,这只是围绕功能或特定任务的“大尝试”。

AFAIK Exceptions are designed for handling things that are out of the developers control like a hardware failure or disconnected network or something similar to that, where the developer might not have the knowledge of the problem, AFAIK异常用于处理开发人员无法控制的事情,例如硬件故障或网络断开或类似的情况,而开发人员可能不知道该问题,

IMHO it is better to check for the value of divider in the expression int r = val/divider; 恕我直言,最好在表达式int r = val/divider;检查divider的值int r = val/divider; than to check for the DivideByZeroException 比检查DivideByZeroException

Using Exceptions to control program flow is 'not done'. 使用“异常”控制程序流“未完成”。 They should be used only to handle exceptional circumstances, when you don't want your entire application to crash. 当您不希望整个应用程序崩溃时,它们仅应用于处理特殊情况。

That said, sometime it is necessary to use Exceptions. 也就是说,有时需要使用异常。 I believe the int.TryParse and other TryParse methods in the .NET Framework use Exceptions, catch them if it doesn't work, and then return false. 我相信.NET Framework中的int.TryParse和其他TryParse方法使用Exceptions,如果不起作用则捕获它们,然后返回false。

If there is no other way of knowing if a Word file is already open, my opinion is that you could use an Exception to do this. 如果没有其他方法可以知道是否已打开Word文件,则我认为您可以使用Exception来执行此操作。 The good thing is that you catch a specific exception, because other things could go wrong. 好消息是您捕获了特定的异常,因为其他情况可能会出错。 The problem is that the IOException could have another source (ie the destination folder is not accesible, etc.). 问题是IOException可能有另一个源(即,目标文件夹不可访问,等等)。 This is true not only for your example, but for all (complex) exception-driven flows. 这不仅适用于您的示例,而且适用于所有(复杂)异常驱动的流。 The TryParse example I gave above is fairly simple, so there, it's not so much of a problem. 我在上面给出的TryParse示例非常简单,因此在这里并没有太大的问题。

Conclusion: don't do it, unless it's the only way you can. 结论:请勿这样做,除非这是您唯一的方法。 And then, try to isolate it in a separate method. 然后,尝试使用单独的方法将其隔离。 This way, if you find a better solution, you can always change your implementation. 这样,如果您找到更好的解决方案,则可以随时更改实现。 Also, try to catch the most specific exception, and keep in mind that exception can have several sources. 另外,请尝试捕获最具体的异常,并记住异常可能有多种来源。

If a routine can satisfy its contract by returning normally, it should do so. 如果例程可以通过正常返回来满足其合同,则应该这样做。 If there is no way a routine can return normally without violating its contract, it should throw an exception. 如果例程无法在不违反其合同的情况下正常返回,则应引发异常。 If a routine's contract is taken as a given, there's really not much room for judgment in deciding whether the routine should throw an exception. 如果将例程的合同作为给定的合同,那么在决定例程是否应该抛出异常时,判断的空间就很小。 It should return or throw based upon the above simple rule. 它应该根据上述简单规则返回或抛出。

The place judgment enters into the equation is in deciding what a routine's contract should be. 地方判断进入方程式是在决定例​​程的合同应该是什么。 A useful pattern is to provide both a "Try" version of a routine and a "Do" version; 一个有用的模式是提供例程的“尝试”版本和“执行”版本。 if the "Try" version is unable to perform the requested action because of a reasonably-anticipated problem, it will indicate that by returning some type of error value; 如果“尝试”版本由于合理预期的问题而无法执行所请求的操作,则它将通过返回某种类型的错误值来指示该错误; if a "Do" version is unable to perform the requested action, for any reason, it will throw an exception. 如果“执行”版本由于任何原因无法执行请求的操作,它将引发异常。

As a simple example, consider "Integer.TryParse" and "Integer.Parse". 作为一个简单的示例,请考虑“ Integer.TryParse”和“ Integer.Parse”。 If one has a string which may or may not be a valid number, one may call Integer.TryParse. 如果一个字符串可能不是有效数字,则可以调用Integer.TryParse。 Integer.TryParse will use a returned flag to indicate whether the parse was successful; Integer.TryParse将使用返回的标志来指示解析是否成功;否则,返回false。 it will return perfectly happily whether the parse succeeded or not, and the caller is responsible for ensuring that TryParse succeeded before trying to use the returned value. 无论解析成功与否,它都会很高兴地返回,并且调用方负责在尝试使用返回的值之前确保TryParse成功。 By contrast, Integer.Parse will only return if the number was parsed successfully. 相比之下,Integer.Parse仅在成功解析数字后才返回。 If the number wasn't valid, Integer.Parse will throw an exception. 如果该数字无效,则Integer.Parse将引发异常。 Calling code may thus use the value returned by Integer.Parse without having to check whether it succeeded; 因此,调用代码可以使用Integer.Parse返回的值,而不必检查它是否成功; if Integer.Parse didn't succeed, it wouldn't have returned. 如果Integer.Parse没有成功,则不会返回。 Note that it's possible for Integer.TryParse to throw exceptions in some truly exceptional cases (eg if unsafe code had made the passed-in String reference point to some other type of object); 注意,在某些真正特殊的情况下(例如,如果不安全的代码使传入的String引用指向某种其他类型的对象),Integer.TryParse可能引发异常。 the only guarantee is that it won't throw in the reasonably-expected cases (eg it's passed a string like "XYZ" instead of one like "123"). 唯一的保证是它不会在合理预期的情况下抛出(例如,它传递的字符串如“ XYZ”而不是诸如“ 123”的字符串)。

A slight enhancement to the Try/Do pattern is to have a routine accept a delegate which will be invoked if something goes wrong. 对Try / Do模式的一个略微增强是使例程接受一个委托,如果出现问题,该委托将被调用。 In many cases, passing a delegate would be overkill, and it's often hard to decide in advance what parameters the delegate should take, but this approach can be advantageous in cases where a decision of whether to muddle on or give up may be determined by outside factors. 在很多情况下,通过委托会太过分,通常很难预先确定委托应采用的参数,但是这种方法在由外部决定是混淆还是放弃的情况下可能是有利的。因素。 Such situations arise in communications scenarios, where a program's proper response to a communications hiccup may be to up a message notifying the user that the program is having difficulty and allow the user to hit "cancel", but to have the program retry the operation a few times if the user does not. 这样的情况出现在通信场景中,其中程序对通信故障的正确响应可能是发出一条消息,通知用户该程序有困难并允许用户按下“取消”,但让程序重试该操作。如果用户没有几次。 If the operation that had to be retried was a small portion of the overall operation to be performed, throwing an exception out to the main line would 'permanently' give up on the larger operation, while performing retries without user interaction could force a user to sit annoyingly long for the computer to give up on an operation the user might know won't possibly succeed (eg because the battery just died on the device he was communicating with). 如果必须重试的操作只占要执行的全部操作的一小部分,则在主线上抛出异常将“永久地”放弃较大的操作,而在没有用户交互的情况下执行重试可能会迫使用户令人讨厌的长时间坐在电脑上,使计算机放弃用户可能知道不会成功的操作(例如,因为电池刚在与之通信的设备上耗尽了)。 Using a callback delegate allows the optimal user interface experience, without tying the communications code to any particular user-interface implementation. 使用回调委托可以提供最佳的用户界面体验,而无需将通信代码绑定到任何特定的用户界面实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM