Windows窗体应用程序中异常处理的最佳实践?

时间:2023-01-13 00:02:00

I'm currently in the process of writing my first Windows Forms application. I've read a few C# books now so I've got a relatively good understanding of what language features C# has to deal with exceptions. They're all quite theoretical however so what I haven't got yet is a feel for how to translate the basic concepts into a good exception-handling model in my application.

我目前正在编写我的第一个Windows窗体应用程序。我现在已经阅读了一些C#书籍,所以我对C#处理异常的语言功能有了比较好的理解。它们都非常理论化,所以我还没有想到如何在我的应用程序中将基本概念转换为一个良好的异常处理模型。

Would anyone like to share any pearls of wisdom on the subject? Post any common mistakes you've seen newbies like myself make, and any general advice on handling exceptions in a way that will my application more stable and robust.

有人愿意分享关于这个主题的任何智慧珍珠吗?发布你看过像我这样的新手所犯的常见错误,以及处理异常的一般建议,使我的应用程序更加稳定和健壮。

The main things I'm currently trying to work out are:

我目前正在努力解决的主要问题是:

  • When should I re-throw an exception?
  • 什么时候应该重新抛出异常?

  • Should I try to have a central error-handling mechanism of some kind?
  • 我应该尝试某种*错误处理机制吗?

  • Do handling exceptions which might be thrown have a performance hit compared with pre-emptively testing things like whether a file on disk exists?
  • 与先前测试诸如磁盘上的文件之类的内容相比,处理可能引发的异常会产生性能损失吗?

  • Should all executable code be enclosed in try-catch-finally blocks?
  • 是否所有可执行代码都包含在try-catch-finally块中?

  • Are there any times when an empty catch block might be acceptable?
  • 有空的挡块是否可以接受?

All advice gratefully received!

感谢所有的建议!

15 个解决方案

#1


78  

A few more bits ...

再多几点......

You absolutely should have a centralized exception handling policy in place. This can be as simple as wrapping Main() in a try/catch, failing fast with a graceful error message to the user. This is the "last resort" exception handler.

您绝对应该有一个集中的异常处理策略。这可以像在try / catch中包装Main()一样简单,快速失败并向用户发送优雅的错误消息。这是“最后的手段”异常处理程序。

Preemptive checks are always correct if feasible, but not always perfect. For example, between the code where you check for a file's existence and the next line where you open it, the file could have been deleted or some other issue may impede your access. You still need try/catch/finally in that world. Use both the preemptive check and the try/catch/finally as appropriate.

如果可行,抢先检查总是正确的,但并不总是完美的。例如,在检查文件存在的代码和打开文件的下一行之间,文件可能已被删除或某些其他问题可能妨碍您访问。在那个世界里你仍然需要try / catch / finally。根据需要同时使用抢先检查和try / catch / finally。

Never "swallow" an exception, except in the most well-documented cases when you are absolutely, positively sure that the exception being thrown is livable. This will almost never be the case. (And if it is, make sure you're swallowing only the specific exception class -- don't ever swallow System.Exception.)

永远不要“吞下”异常,除非在绝对正确记录的情况下,确定抛出的异常是适合居住的。这几乎不会是这种情况。 (如果确实如此,请确保您只吞下特定的异常类 - 不要吞下System.Exception。)

When building libraries (used by your app), do not swallow exceptions, and do not be afraid to let the exceptions bubble up. Do not re-throw unless you have something useful to add. Do not ever (in C#) do this:

在构建库(由您的应用程序使用)时,不要吞下异常,也不要害怕异常冒泡。除非你有一些有用的东西要添加,否则不要重新抛出。不要(在C#中)这样做:

throw ex;

As you will erase the call stack. If you must re-throw (which is occasionally necessary, such as when using the Exception Handling Block of Enterprise Library), use the following:

因为你将擦除调用堆栈。如果必须重新抛出(有时需要,例如使用企业库的异常处理块时),请使用以下命令:

throw;

At the end of the day, the very vast majority of exceptions thrown by a running application should be exposed somewhere. They should not be exposed to end users (as they often contain proprietary or otherwise valuable data), but rather usually logged, with administrators notified of the exception. The user can be presented with a generic dialog box, maybe with a reference number, to keep things simple.

在一天结束时,正在运行的应用程序抛出的绝大多数异常都应该暴露在某处。它们不应该暴露给最终用户(因为它们通常包含专有或其他有价值的数据),而是通常记录,并通知管理员异常。可以向用户呈现通用对话框,可以带有参考编号,以使事情变得简单。

Exception handling in .NET is more art than science. Everyone will have their favorites to share here. These are just a few of the tips I've picked up using .NET since day 1, techniques which have saved my bacon on more than one occasion. Your mileage may vary.

.NET中的异常处理更多的是艺术而非科学。每个人都会在这里分享他们的最爱。这些只是我从第1天开始使用.NET获得的一些技巧,这些技巧不止一次地保存了我的培根。你的旅费可能会改变。

#2


61  

There is an excellent code CodeProject article here. Here are a couple of highlights:

这里有一篇优秀的代码CodeProject文章。以下是一些亮点:

  • Plan for the worst*
  • 计划最坏的*

  • Check it early
  • 早点检查

  • Don't trust external data
  • 不要相信外部数据

  • The only reliable devices are: the video, the mouse and keyboard.
  • 唯一可靠的设备是:视频,鼠标和键盘。

  • Writes can fail, too
  • 写作也可能失败

  • Code Safely
  • Don't throw new Exception()
  • 不要抛出新的异常()

  • Don't put important exception information on the Message field
  • 不要在Message字段上放置重要的异常信息

  • Put a single catch (Exception ex) per thread
  • 每个线程放一个catch(Exception ex)

  • Generic Exceptions caught should be published
  • 应发布通用异常

  • Log Exception.ToString(); never log only Exception.Message!
  • Log Exception.ToString();永远不会只记录Exception.Message!

  • Don't catch (Exception) more than once per thread
  • 每个线程不要多次捕获(异常)

  • Don't ever swallow exceptions
  • 不要吞下异常

  • Cleanup code should be put in finally blocks
  • 清理代码应该放在finally块中

  • Use "using" everywhere
  • 到处使用“使用”

  • Don't return special values on error conditions
  • 不要在错误条件下返回特殊值

  • Don't use exceptions to indicate absence of a resource
  • 不要使用异常来指示缺少资源

  • Don't use exception handling as means of returning information from a method
  • 不要使用异常处理作为从方法返回信息的方法

  • Use exceptions for errors that should not be ignored
  • 对不应忽略的错误使用异常

  • Don't clear the stack trace when re-throwing an exception
  • 重新抛出异常时,请勿清除堆栈跟踪

  • Avoid changing exceptions without adding semantic value
  • 避免在不添加语义值的情况下更改异常

  • Exceptions should be marked [Serializable]
  • 应将例外标记为[Serializable]

  • When in doubt, don't Assert, throw an Exception
  • 如有疑问,请不要断言,抛出异常

  • Each exception class should have at least the three original constructors
  • 每个异常类至少应该有三个原始构造函数

  • Be careful when using the AppDomain.UnhandledException event
  • 使用AppDomain.UnhandledException事件时要小心

  • Don't reinvent the wheel
  • 不要重新发明*

  • Don't use Unstructured Error Handling (VB.Net)
  • 不要使用非结构化错误处理(VB.Net)

#3


14  

All of the advice posted here so far is good and worth heeding.

到目前为止,这里发布的所有建议都很好,值得注意。

One thing I'd like to expand on is your question "Do handling exceptions which might be thrown have a performance hit compared with pre-emptively testing things like whether a file on disk exists?"

我想要扩展的一件事是你的问题“与先前测试磁盘上的文件是否存在等问题相比,处理可能抛出的异常会产生性能损失吗?”

The naive rule of thumb is "try/catch blocks are expensive." That's not actually true. Trying isn't expensive. It's the catching, where the system has to create an Exception object and load it up with the stack trace, that's expensive. There are many cases in which the exception is, well, exceptional enough that it's perfectly fine to wrap the code in a try/catch block.

天真的经验法则是“尝试/捕获块很昂贵”。事实并非如此。尝试并不昂贵。这是捕获,系统必须创建一个Exception对象并使用堆栈跟踪加载它,这是昂贵的。在许多情况下,异常足够特殊,将代码包装在try / catch块中完全没问题。

For instance, if you're populating a Dictionary, this:

例如,如果您正在填充字典,则:

try
{
   dict.Add(key, value);
}
catch(KeyException)
{
}

is often faster than doing this:

通常比这样做更快:

if (!dict.ContainsKey(key))
{
   dict.Add(key, value);
}

for every single item you're adding, because the exception only gets thrown when you are adding a duplicate key. (LINQ aggregate queries do this.)

对于您要添加的每个项目,因为只有在添加重复键时才会抛出异常。 (LINQ聚合查询执行此操作。)

In the example you gave, I'd use try/catch almost without thinking. First, just because the file exists when you check for it doesn't mean that it's going to exist when you open it, so you should really handle the exception anyway.

在你给出的例子中,我几乎不假思索地使用try / catch。首先,只是因为当你检查它时文件存在并不意味着当你打开它时它会存在,所以你应该真正处理异常。

Second, and I think more importantly, unless your a) your process is opening thousands of files and b) the odds of a file it's trying to open not existing are not trivially low, the performance hit of creating the exception is not something you're ever going to notice. Generally speaking, when your program is trying to open a file, it's only trying to open one file. That's a case where writing safer code is almost certainly going to be better than writing the fastest possible code.

其次,我认为更重要的是,除非你的a)你的流程正在打开成千上万的文件,并且b)尝试打开不存在的文件的几率不是很低,创建例外的性能不是你的'我会注意到的。一般来说,当您的程序尝试打开文件时,它只会尝试打开一个文件。在这种情况下,编写更安全的代码几乎肯定会比编写最快的代码更好。

#4


14  

Note that Windows Forms has it own exception handling mechanism. If a button in form is clicked and its handler throws an exception which isn't caught in the handler, Windows Forms will display its own Unhandled Exception Dialog.

请注意,Windows窗体具有自己的异常处理机制。如果单击表单中的按钮并且其处理程序抛出未在处理程序中捕获的异常,则Windows窗体将显示其自己的“未处理的异常”对话框。

To prevent the Unhandled Exception Dialog to be displayed and catch such exceptions for logging and/or for providing your own error dialog you can attach to the Application.ThreadException event before the call to Application.Run() in your Main() method.

要防止显示未处理的异常对话框并捕获此类异常以进行日志记录和/或提供您自己的错误对话框,您可以在Main()方法中调用Application.Run()之前附加到Application.ThreadException事件。

#5


8  

Here are a few guidelines that I follow

以下是我遵循的一些指导原则

  1. Fail-Fast: This is more of a exception generating guideline, For every assumption that you make and every parameter that you are getting into a function do a check to make sure that you're starting off with the right data and that the assumptions you're making are correct. Typical checks include, argument not null, argument in expected range etc.

    快速失败:这是一个异常生成指南,对于您所做的每个假设以及您进入函数的每个参数都要进行检查,以确保您从正确的数据开始并假设您'制作是正确的。典型的检查包括,参数not null,预期范围内的参数等。

  2. When rethrowing preserve stack trace - This simply translates to using throw when rethrowing instead of throw new Exception(). Alternatively if you feel that you can add more information then wrap the original exception as an inner exception. But if you're catching an exception only to log it then definitely use throw;

    当重新抛出保留堆栈跟踪时 - 这简单地转换为在重新抛出时使用throw而不是throw new Exception()。或者,如果您认为可以添加更多信息,则将原始异常包装为内部异常。但是,如果您只是为了记录它而捕获异常,那么肯定会使用throw;

  3. Do not catch exceptions that you cannot handle, so don't worry about things like OutOfMemoryException because if they occur you won't be able to do much anyways.

    不要捕获你无法处理的异常,所以不要担心像OutOfMemoryException这样的事情,因为如果它们发生,你将无法做任何事情。

  4. Do hook global exception handlers and make sure to log as much information as possible. For winforms hook both the appdomain and thread unhandled exception events.

    挂钩全局异常处理程序并确保记录尽可能多的信息。对于winforms挂钩appdomain和线程未处理的异常事件。

  5. Performance should only be taken into consideration when you've analyzed the code and seen that it's causing a performance bottleneck, by default optimize for readability and design. So about your original question on the file existence check, I would say it depends, If you can do something about the file not being there, then yes do that check otherwise if all you're going to do is throw an exception if the file's not there then I don't see the point.

    只有在分析了代码并发现它导致性能瓶颈时才应考虑性能,默认情况下优化可读性和设计。所以关于文件存在检查的原始问题,我会说这取决于,如果你可以对文件不存在做一些事情,那么是这样检查否则如果你要做的就是抛出异常,如果文件是不是那里我没有看到这一点。

  6. There are definitely times when empty catch blocks are required, I think people who say otherwise have not worked on codebases that have evolved over several releases. But they should be commented and reviewed to make sure that they're really needed. The most typical example is developers using try/catch to convert string to integer instead of using ParseInt().

    肯定有些时候需要空的catch块,我认为那些说不然的人还没有处理过几个版本的代码库。但是应该对它们进行评论和评审,以确保它们真的需要它们。最典型的例子是开发人员使用try / catch将字符串转换为整数而不是使用ParseInt()。

  7. If you expect the caller of your code to be able to handle error conditions then create custom exceptions that detail what the un excepected situation is and provide relevant information. Otherwise just stick to built-in exception types as much as possible.

    如果您希望代码的调用者能够处理错误条件,那么创建自定义异常,详细说明未处理的情况并提供相关信息。否则只要尽可能坚持内置的异常类型。

#6


4  

I like the philosophy of not catching anything I don't intend on handling, whatever handling means in my particular context.

我喜欢不抓住任何我不打算处理的东西的哲学,无论在我的特定环境中处理什么。

I hate it when I see code such as:

当我看到以下代码时,我讨厌它:

try
{
   // some stuff is done here
}
catch
{
}

I have seen this from time to time and it is quite difficult to find problems when someone 'eats' the exceptions. A coworker I had does this and it tends to end up being a contributor to a steady stream of issues.

我不时地看到这一点,当有人'吃'例外时很难找到问题。我有一个同事这样做,它往往最终成为问题源源不断的贡献者。

I re-throw if there is something that my particular class needs to do in response to an exception but the problem needs to be bubbled out to however called the method where it happened.

如果我的特定类需要做一些事情来响应异常,我会重新抛出但是问题需要冒出来然后调用它发生的方法。

I think code should be written proactively and that exceptions should be for exceptional situations, not to avoid testing for conditions.

我认为代码应该是主动编写的,异常应该是针对特殊情况,而不是为了避免测试条件。

#7


4  

I'm just on my way out but will give you a brief run down on where to use exception handling. I will attempt to address your other points when I return :)

我刚刚离开,但会简要介绍一下使用异常处理的地方。当我回来时,我会尝试解决你的其他问题:)

  1. Explicitly check for all known error conditions*
  2. 明确检查所有已知错误情况*

  3. Add a try/catch around the code if your are unsure if you were able to handle all cases
  4. 如果您不确定是否能够处理所有情况,请在代码周围添加try / catch

  5. Add a try/catch around the code if the .NET interface you are calling throws an exception
  6. 如果要调用的.NET接口抛出异常,请在代码周围添加try / catch

  7. Add a try/catch around the code if it crosses a complexity threshold for you
  8. 如果代码超过了复杂性阈值,请在代码周围添加try / catch

  9. Add a try/catch around the code if for a sanity check: You are asserting THIS SHOULD NEVER HAPPEN
  10. 如果要进行健全性检查,请在代码周围添加一个try / catch:您声明这应该永远不会发生

  11. As a general rule, I do not use exceptions as a replacement for return codes. This is fine for .NET, but not me. I do have exceptions (hehe) to this rule though, it depends on the architecture of the application your are working on as well.
  12. 作为一般规则,我不使用异常作为返回代码的替代。这对.NET来说很好,但不是我。我确实对此规则有异常(呵呵),这取决于您正在处理的应用程序的体系结构。

*Within reason. There is no need to check to see if say a cosmic ray hit your data causing a couple bits to get flipped. Understanding what is "reasonable" is an acquired skill for an engineer. It's hard to quantify, yet easy to intuit. That is, I can easily explain why I use a try/catch in any particular instance, yet I am hard pressed to imbue another with this same knowledge.

*在合理范围内。没有必要检查宇宙射线是否会击中你的数据导致一些比特被翻转。理解什么是“合理的”是工程师获得的技能。它很难量化,但很容易直观。也就是说,我可以很容易地解释为什么我在任何特定的实例中使用try / catch,但我很难用同样的知识灌输另一个。

I for one tend to steer away from heavily exception based architectures. try/catch doesn't have a performance hit as such, the hit comes in when the exception is thrown and the code might have to walk up several levels of the call stack before something handles it.

我倾向于避开基于异常的大型架构。 try / catch没有这样的性能命中,当抛出异常并且代码可能必须在处理它之前走几层调用堆栈时命中。

#8


3  

The golden rule that have tried to stick to is handle the exception as close to the source as possible.

试图坚持的黄金法则是尽可能靠近源处理异常。

If you must re-throw an exception try to add to it, re-throwing a FileNotFoundException does not help much but throwing a ConfigurationFileNotFoundException will allow it to be captured and acted upon somewhere up the chain.

如果你必须重新抛出一个异常尝试添加它,重新抛出一个FileNotFoundException并没有多大帮助,但抛出一个ConfigurationFileNotFoundException将允许它被捕获并在链的某个地方采取行动。

Another rule I try to follow is not to use try/catch as a form of program flow, so I do verify files/connections, ensure objects have been initiated, ect.. prior to using them. Try/catch should be for Exceptions, things you can not control.

我尝试遵循的另一个规则是不使用try / catch作为程序流的一种形式,所以我确实验证了文件/连接,确保对象已经启动,等等..在使用它们之前。尝试/捕获应该是例外,你无法控制的事情。

As for an empty catch block, if you are doing anything of importance in the code that generated the exception you should re-throw the exception at a minimum. If there is no consequences of the code that threw the exception not running why did you write it in the first place.

至于一个空的catch块,如果你在生成异常的代码中做了任何重要的事情,你应该至少重新抛出异常。如果没有运行异常的代码没有后果,你为什么要首先编写它。

#9


2  

Exceptions are expensive but necessary. You don't need to wrap everything in a try catch but you do need to ensure that exceptions are always caught eventually. Much of it will depend on your design.

例外情况既昂贵又必要。您不需要在try catch中包装所有内容,但确实需要确保始终捕获异常。其中很大程度上取决于您的设计。

Don't re-throw if letting the exception rise will do just as well. Never let errors pass unnoticed.

如果让异常上升同样可以做,也不要重新抛出。永远不要忽视错误。

example:

void Main()
{
  try {
    DoStuff();
  }
  catch(Exception ex) {
    LogStuff(ex.ToString());
  }

void DoStuff() {
... Stuff ...
}

If DoStuff goes wrong you'll want it to bail anyway. The exception will get thrown up to main and you'll see the train of events in the stack trace of ex.

如果DoStuff出错了,你还是希望它保释。异常将被抛到main,你会在ex的堆栈跟踪中看到一系列事件。

#10


1  

When should I re-throw an exception?

什么时候应该重新抛出异常?

Everywhere, but end user methods... like button click handlers

无处不在,但最终用户方法......就像按钮点击处理程序一样

Should I try to have a central error-handling mechanism of some kind?

我应该尝试某种*错误处理机制吗?

I write a log file... pretty easy for a WinForm app

我写了一个日志文件......对于WinForm应用来说非常简单

Do handling exceptions which might be thrown have a performance hit compared with pre-emptively testing things like whether a file on disk exists?

与先前测试诸如磁盘上的文件之类的内容相比,处理可能引发的异常会产生性能损失吗?

I'm not sure about this, but I believe it is a good practice to thow exceptions... I mean you can ask whether a file exists and if it doesn't throw a FileNotFoundException

我不确定这一点,但我认为提示异常是一个好习惯...我的意思是你可以询问文件是否存在以及它是否不会抛出FileNotFoundException

Should all executable code be enclosed in try-catch-finally blocks?

是否所有可执行代码都包含在try-catch-finally块中?

yeap

Are there any times when an empty catch block might be acceptable?

有空的挡块是否可以接受?

Yes, let's say you want to show a date, but you have no clue how that date was stores (dd/mm/yyyy, mm/dd/yyyy, etc) you try tp parse it but if it fails just keep going... if it is irrelevant to you... I would say yes, there is

是的,假设您要显示日期,但您不知道该日期是如何存储(dd / mm / yyyy,mm / dd / yyyy等),您尝试解析它但如果失败则继续...如果它与你无关......我会说是,有

#11


1  

The one thing I learned very quickly was to enclose absolutely every chunk of code that interacts with anything outside the flow of my program (i.e. File System, Database Calls, User Input) with try-catch blocks. Try-catch can incur a performance hit, but usually in these places in your code it won't be noticeable and it will pay for itself with safety.

I have used empty catch-blocks in places where the user might do something that isn't really "incorrect", but it can throw an exception...an example that comes to mind is in a GridView if the user DoubleCLicks the gray placeholder cell on the top-left it will fire the CellDoubleClick event, but the cell doesn't belong to a row. In that case, you dont really need to post a message but if you don't catch it it will throw an unhandled exception error to the user.

我很快就学到的一件事就是绝对包含与我的程序流程之外的任何东西(即文件系统,数据库调用,用户输入)交互的每一块代码和try-catch块。尝试捕获可能会导致性能损失,但通常在代码中的这些位置它不会引人注意,它将为安全带来收益。我在用户可能会做一些并非真正“不正确”的地方使用了空的catch块,但是它可以抛出一个异常...如果用户DoubleCLicks灰色占位符,我想到的一个例子是在GridView中左上角的单元格将触发CellDoubleClick事件,但该单元格不属于某一行。在这种情况下,你真的不需要发布消息,但如果你没有捕获它,它将向用户抛出未处理的异常错误。

#12


1  

When re-throwing an exception the key word throw by it self. This will throw the caught exception and still will be able to use stack trace to see where it came from.

当重新抛出异常时,关键词会自行抛出。这将抛出捕获的异常,仍然可以使用堆栈跟踪来查看它的来源。

Try
{
int a = 10 / 0;
}
catch(exception e){
//error logging
throw;
}

doing this will cause the stack trace to end in the catch statement. (avoid this)

这样做会导致堆栈跟踪在catch语句中结束。 (避免这个)

catch(Exception e)
// logging
throw e;
}

#13


1  

n my experience I've seen fit to catch exceptions when I know I'm going to be creating them. For instances when I'm in a web application and I'm doing a Response.Redirect, I know I'll be getting a System.ThreadAbortException. Since it's intentional I just have a catch for the specific type and just swallow it.

根据我的经验,当我知道我将创建它们时,我认为适合捕捉异常。对于我在Web应用程序中并且正在执行Response.Redirect的情况,我知道我将获得System.ThreadAbortException。因为它是有意的,我只是抓住特定类型并且只是吞下它。

try
{
/*Doing stuff that may cause an exception*/
Response.Redirect("http:\\www.somewhereelse.com");
}
catch (ThreadAbortException tex){/*Ignore*/}
catch (Exception ex){/*HandleException*/}

#14


1  

I deeply agree the rule of:

我非常同意以下规则:

  • Never let errors pass unnoticed.
  • 永远不要忽视错误。

The reason is that:

原因是:

  • When you first write down the code, most likely you won't have the full knowledge of 3-party code, .NET FCL lirary, or your co-workers latest contributions. In reality you cannot refuse to write code until you know every exception possiblity well. So
  • 当您第一次写下代码时,很可能您不会完全了解三方代码,.NET FCL或者您的同事最新贡献。实际上,在你完全了解每个异常可能性之前,你不能拒绝编写代码。所以

  • I constanly find that I use try/catch(Exception ex) just because I want to protected myself from unknown things, and, as you noticed, I catch Exception, not the more specific such as OutOfMemoryException etc. And, I always make the exception being popped up to me(or the QA) by ForceAssert.AlwaysAssert(false, ex.ToString() );
  • 我常常发现我使用try / catch(Exception ex)只是因为我想保护自己免受未知事物的影响,而且,正如你所注意到的,我捕获了Exception,而不是更具体的例如OutOfMemoryException等。而且,我总是做出异常通过ForceAssert.AlwaysAssert(false,ex.ToString())弹出给我(或QA);

ForceAssert.AlwaysAssert is my personal way of Trace.Assert just regardless of whether the DEBUG/TRACE macro is defined.

ForceAssert.AlwaysAssert是我个人的Trace.Assert方式,无论是否定义了DEBUG / TRACE宏。

The development cycle maybe: I noticed the ugly Assert dialog or someone else complain to me about it, then I come back to the code and figure out the reason to raise the exception and decide how to process it.

开发周期可能是:我注意到丑陋的Assert对话框或其他人向我抱怨它,然后我回到代码并找出引发异常的原因并决定如何处理它。

By this way I can write down MY code in a short time and protected me from unknown domain, but always being noticed if the abnormal things happened, by this way the system got safe and more safety.

通过这种方式,我可以在短时间内写下我的代码并保护我免受未知领域的影响,但是如果异常事件发生,总会被注意到,通过这种方式系统变得安全且更安全。

I know many of you wont agree with me because a developer should known every detail of his/her code, frankly, I'm also a purist in the old days. But nowdays I learned that the above policy is more pragmatic.

我知道很多人不同意我的看法,因为开发人员应该知道他/她的代码的每一个细节,坦率地说,我在过去也是一个纯粹主义者。但是现在我了解到上述政策更加务实。

For WinForms code, a golden rule I always obey is:

对于WinForms代码,我始终遵守的一条黄金法则是:

  • Always try/catch(Exception) your event handler code
  • 总是尝试/捕获(例外)您的事件处理程序代码

this will protected your UI being always usable.

这将保护您的UI始终可用。

For performance hit, performance penalty only happens when the code reachs catch, executing try code without the actual exception raised has no significant effect.

对于性能损失,仅在代码达到catch时执行性能损失,执行try代码而不会引发实际异常没有显着影响。

Exception should be happened with little chance, otherwise it's not exceptions.

应该以很少的机会发生异常,否则不是例外。

#15


0  

You have to think about the user. The application crash is the last thing the user wants. Therefore any operation that can fail should have a try catch block at the ui level. It's not necessary to use try catch in every method, but every time the user does something it must be able to handle generic exceptions. That by no means frees you from checking everything to prevent exceptions in the first case, but there is no complex application without bugs and the OS can easily add unexpected problems, therefore you must anticipate the unexpected and make sure if a user wants to use one operation there won't be data loss because the app crashes. There is no need to ever let your app crash, if you catch exceptions it will never be in an indeterminate state and the user is ALWAYS inconvenienced by a crash. Even if the exception is at the top most level, not crashing means the user can quickly reproduce the exception or at least record the error message and therefore greatly help you to fix the problem. Certainly a lot more than getting a simple error message and then seeing only windows error dialog or something like that.

你必须考虑用户。应用程序崩溃是用户想要的最后一件事。因此,任何可能失败的操作都应该在ui级别有一个try catch块。没有必要在每个方法中使用try catch,但每次用户执行某些操作时,它必须能够处理一般异常。这绝不会让你在第一种情况下检查所有内容以防止异常,但是没有没有错误的复杂应用程序,操作系统可以轻松添加意外问题,因此你必须预见到意外情况,并确保用户是否想要使用一个操作不会因为应用程序崩溃而导致数据丢失。没有必要让您的应用程序崩溃,如果您捕获异常,它将永远不会处于不确定状态,并且用户总是会因崩溃而感到不便。即使异常处于*别,也不会崩溃意味着用户可以快速重现异常或至少记录错误消息,因此可以帮助您解决问题。当然不仅仅是获取一个简单的错误消息,然后只看到Windows错误对话框或类似的东西。

That's why you must NEVER just be conceited and think your app has no bugs, that is not guaranteed. And it is a very small effort to wrap some try catch blocks about the appropriate code and show an error message / log the error.

这就是为什么你绝对不要只是自负,并认为你的应用没有错误,这是不能保证的。并且,对于适当的代码包装一些try catch块并显示错误消息/记录错误是一个非常小的努力。

As a user, I certainly get seriously pissed whenever a brows or office app or whatever crashes. If the exception is so high that the app can't continue it's better to display that message and tell the user what to do (restart, fix some os settings, report the bug, etc.) than to simply crash and that's it.

作为一个用户,无论什么时候眉毛或办公室应用程序或任何崩溃,我当然会非常生气。如果异常太高以至于应用程序无法继续,那么最好显示该消息并告诉用户该做什么(重新启动,修复一些操作系统设置,报告错误等),而不是简单地崩溃,就是这样。

#1


78  

A few more bits ...

再多几点......

You absolutely should have a centralized exception handling policy in place. This can be as simple as wrapping Main() in a try/catch, failing fast with a graceful error message to the user. This is the "last resort" exception handler.

您绝对应该有一个集中的异常处理策略。这可以像在try / catch中包装Main()一样简单,快速失败并向用户发送优雅的错误消息。这是“最后的手段”异常处理程序。

Preemptive checks are always correct if feasible, but not always perfect. For example, between the code where you check for a file's existence and the next line where you open it, the file could have been deleted or some other issue may impede your access. You still need try/catch/finally in that world. Use both the preemptive check and the try/catch/finally as appropriate.

如果可行,抢先检查总是正确的,但并不总是完美的。例如,在检查文件存在的代码和打开文件的下一行之间,文件可能已被删除或某些其他问题可能妨碍您访问。在那个世界里你仍然需要try / catch / finally。根据需要同时使用抢先检查和try / catch / finally。

Never "swallow" an exception, except in the most well-documented cases when you are absolutely, positively sure that the exception being thrown is livable. This will almost never be the case. (And if it is, make sure you're swallowing only the specific exception class -- don't ever swallow System.Exception.)

永远不要“吞下”异常,除非在绝对正确记录的情况下,确定抛出的异常是适合居住的。这几乎不会是这种情况。 (如果确实如此,请确保您只吞下特定的异常类 - 不要吞下System.Exception。)

When building libraries (used by your app), do not swallow exceptions, and do not be afraid to let the exceptions bubble up. Do not re-throw unless you have something useful to add. Do not ever (in C#) do this:

在构建库(由您的应用程序使用)时,不要吞下异常,也不要害怕异常冒泡。除非你有一些有用的东西要添加,否则不要重新抛出。不要(在C#中)这样做:

throw ex;

As you will erase the call stack. If you must re-throw (which is occasionally necessary, such as when using the Exception Handling Block of Enterprise Library), use the following:

因为你将擦除调用堆栈。如果必须重新抛出(有时需要,例如使用企业库的异常处理块时),请使用以下命令:

throw;

At the end of the day, the very vast majority of exceptions thrown by a running application should be exposed somewhere. They should not be exposed to end users (as they often contain proprietary or otherwise valuable data), but rather usually logged, with administrators notified of the exception. The user can be presented with a generic dialog box, maybe with a reference number, to keep things simple.

在一天结束时,正在运行的应用程序抛出的绝大多数异常都应该暴露在某处。它们不应该暴露给最终用户(因为它们通常包含专有或其他有价值的数据),而是通常记录,并通知管理员异常。可以向用户呈现通用对话框,可以带有参考编号,以使事情变得简单。

Exception handling in .NET is more art than science. Everyone will have their favorites to share here. These are just a few of the tips I've picked up using .NET since day 1, techniques which have saved my bacon on more than one occasion. Your mileage may vary.

.NET中的异常处理更多的是艺术而非科学。每个人都会在这里分享他们的最爱。这些只是我从第1天开始使用.NET获得的一些技巧,这些技巧不止一次地保存了我的培根。你的旅费可能会改变。

#2


61  

There is an excellent code CodeProject article here. Here are a couple of highlights:

这里有一篇优秀的代码CodeProject文章。以下是一些亮点:

  • Plan for the worst*
  • 计划最坏的*

  • Check it early
  • 早点检查

  • Don't trust external data
  • 不要相信外部数据

  • The only reliable devices are: the video, the mouse and keyboard.
  • 唯一可靠的设备是:视频,鼠标和键盘。

  • Writes can fail, too
  • 写作也可能失败

  • Code Safely
  • Don't throw new Exception()
  • 不要抛出新的异常()

  • Don't put important exception information on the Message field
  • 不要在Message字段上放置重要的异常信息

  • Put a single catch (Exception ex) per thread
  • 每个线程放一个catch(Exception ex)

  • Generic Exceptions caught should be published
  • 应发布通用异常

  • Log Exception.ToString(); never log only Exception.Message!
  • Log Exception.ToString();永远不会只记录Exception.Message!

  • Don't catch (Exception) more than once per thread
  • 每个线程不要多次捕获(异常)

  • Don't ever swallow exceptions
  • 不要吞下异常

  • Cleanup code should be put in finally blocks
  • 清理代码应该放在finally块中

  • Use "using" everywhere
  • 到处使用“使用”

  • Don't return special values on error conditions
  • 不要在错误条件下返回特殊值

  • Don't use exceptions to indicate absence of a resource
  • 不要使用异常来指示缺少资源

  • Don't use exception handling as means of returning information from a method
  • 不要使用异常处理作为从方法返回信息的方法

  • Use exceptions for errors that should not be ignored
  • 对不应忽略的错误使用异常

  • Don't clear the stack trace when re-throwing an exception
  • 重新抛出异常时,请勿清除堆栈跟踪

  • Avoid changing exceptions without adding semantic value
  • 避免在不添加语义值的情况下更改异常

  • Exceptions should be marked [Serializable]
  • 应将例外标记为[Serializable]

  • When in doubt, don't Assert, throw an Exception
  • 如有疑问,请不要断言,抛出异常

  • Each exception class should have at least the three original constructors
  • 每个异常类至少应该有三个原始构造函数

  • Be careful when using the AppDomain.UnhandledException event
  • 使用AppDomain.UnhandledException事件时要小心

  • Don't reinvent the wheel
  • 不要重新发明*

  • Don't use Unstructured Error Handling (VB.Net)
  • 不要使用非结构化错误处理(VB.Net)

#3


14  

All of the advice posted here so far is good and worth heeding.

到目前为止,这里发布的所有建议都很好,值得注意。

One thing I'd like to expand on is your question "Do handling exceptions which might be thrown have a performance hit compared with pre-emptively testing things like whether a file on disk exists?"

我想要扩展的一件事是你的问题“与先前测试磁盘上的文件是否存在等问题相比,处理可能抛出的异常会产生性能损失吗?”

The naive rule of thumb is "try/catch blocks are expensive." That's not actually true. Trying isn't expensive. It's the catching, where the system has to create an Exception object and load it up with the stack trace, that's expensive. There are many cases in which the exception is, well, exceptional enough that it's perfectly fine to wrap the code in a try/catch block.

天真的经验法则是“尝试/捕获块很昂贵”。事实并非如此。尝试并不昂贵。这是捕获,系统必须创建一个Exception对象并使用堆栈跟踪加载它,这是昂贵的。在许多情况下,异常足够特殊,将代码包装在try / catch块中完全没问题。

For instance, if you're populating a Dictionary, this:

例如,如果您正在填充字典,则:

try
{
   dict.Add(key, value);
}
catch(KeyException)
{
}

is often faster than doing this:

通常比这样做更快:

if (!dict.ContainsKey(key))
{
   dict.Add(key, value);
}

for every single item you're adding, because the exception only gets thrown when you are adding a duplicate key. (LINQ aggregate queries do this.)

对于您要添加的每个项目,因为只有在添加重复键时才会抛出异常。 (LINQ聚合查询执行此操作。)

In the example you gave, I'd use try/catch almost without thinking. First, just because the file exists when you check for it doesn't mean that it's going to exist when you open it, so you should really handle the exception anyway.

在你给出的例子中,我几乎不假思索地使用try / catch。首先,只是因为当你检查它时文件存在并不意味着当你打开它时它会存在,所以你应该真正处理异常。

Second, and I think more importantly, unless your a) your process is opening thousands of files and b) the odds of a file it's trying to open not existing are not trivially low, the performance hit of creating the exception is not something you're ever going to notice. Generally speaking, when your program is trying to open a file, it's only trying to open one file. That's a case where writing safer code is almost certainly going to be better than writing the fastest possible code.

其次,我认为更重要的是,除非你的a)你的流程正在打开成千上万的文件,并且b)尝试打开不存在的文件的几率不是很低,创建例外的性能不是你的'我会注意到的。一般来说,当您的程序尝试打开文件时,它只会尝试打开一个文件。在这种情况下,编写更安全的代码几乎肯定会比编写最快的代码更好。

#4


14  

Note that Windows Forms has it own exception handling mechanism. If a button in form is clicked and its handler throws an exception which isn't caught in the handler, Windows Forms will display its own Unhandled Exception Dialog.

请注意,Windows窗体具有自己的异常处理机制。如果单击表单中的按钮并且其处理程序抛出未在处理程序中捕获的异常,则Windows窗体将显示其自己的“未处理的异常”对话框。

To prevent the Unhandled Exception Dialog to be displayed and catch such exceptions for logging and/or for providing your own error dialog you can attach to the Application.ThreadException event before the call to Application.Run() in your Main() method.

要防止显示未处理的异常对话框并捕获此类异常以进行日志记录和/或提供您自己的错误对话框,您可以在Main()方法中调用Application.Run()之前附加到Application.ThreadException事件。

#5


8  

Here are a few guidelines that I follow

以下是我遵循的一些指导原则

  1. Fail-Fast: This is more of a exception generating guideline, For every assumption that you make and every parameter that you are getting into a function do a check to make sure that you're starting off with the right data and that the assumptions you're making are correct. Typical checks include, argument not null, argument in expected range etc.

    快速失败:这是一个异常生成指南,对于您所做的每个假设以及您进入函数的每个参数都要进行检查,以确保您从正确的数据开始并假设您'制作是正确的。典型的检查包括,参数not null,预期范围内的参数等。

  2. When rethrowing preserve stack trace - This simply translates to using throw when rethrowing instead of throw new Exception(). Alternatively if you feel that you can add more information then wrap the original exception as an inner exception. But if you're catching an exception only to log it then definitely use throw;

    当重新抛出保留堆栈跟踪时 - 这简单地转换为在重新抛出时使用throw而不是throw new Exception()。或者,如果您认为可以添加更多信息,则将原始异常包装为内部异常。但是,如果您只是为了记录它而捕获异常,那么肯定会使用throw;

  3. Do not catch exceptions that you cannot handle, so don't worry about things like OutOfMemoryException because if they occur you won't be able to do much anyways.

    不要捕获你无法处理的异常,所以不要担心像OutOfMemoryException这样的事情,因为如果它们发生,你将无法做任何事情。

  4. Do hook global exception handlers and make sure to log as much information as possible. For winforms hook both the appdomain and thread unhandled exception events.

    挂钩全局异常处理程序并确保记录尽可能多的信息。对于winforms挂钩appdomain和线程未处理的异常事件。

  5. Performance should only be taken into consideration when you've analyzed the code and seen that it's causing a performance bottleneck, by default optimize for readability and design. So about your original question on the file existence check, I would say it depends, If you can do something about the file not being there, then yes do that check otherwise if all you're going to do is throw an exception if the file's not there then I don't see the point.

    只有在分析了代码并发现它导致性能瓶颈时才应考虑性能,默认情况下优化可读性和设计。所以关于文件存在检查的原始问题,我会说这取决于,如果你可以对文件不存在做一些事情,那么是这样检查否则如果你要做的就是抛出异常,如果文件是不是那里我没有看到这一点。

  6. There are definitely times when empty catch blocks are required, I think people who say otherwise have not worked on codebases that have evolved over several releases. But they should be commented and reviewed to make sure that they're really needed. The most typical example is developers using try/catch to convert string to integer instead of using ParseInt().

    肯定有些时候需要空的catch块,我认为那些说不然的人还没有处理过几个版本的代码库。但是应该对它们进行评论和评审,以确保它们真的需要它们。最典型的例子是开发人员使用try / catch将字符串转换为整数而不是使用ParseInt()。

  7. If you expect the caller of your code to be able to handle error conditions then create custom exceptions that detail what the un excepected situation is and provide relevant information. Otherwise just stick to built-in exception types as much as possible.

    如果您希望代码的调用者能够处理错误条件,那么创建自定义异常,详细说明未处理的情况并提供相关信息。否则只要尽可能坚持内置的异常类型。

#6


4  

I like the philosophy of not catching anything I don't intend on handling, whatever handling means in my particular context.

我喜欢不抓住任何我不打算处理的东西的哲学,无论在我的特定环境中处理什么。

I hate it when I see code such as:

当我看到以下代码时,我讨厌它:

try
{
   // some stuff is done here
}
catch
{
}

I have seen this from time to time and it is quite difficult to find problems when someone 'eats' the exceptions. A coworker I had does this and it tends to end up being a contributor to a steady stream of issues.

我不时地看到这一点,当有人'吃'例外时很难找到问题。我有一个同事这样做,它往往最终成为问题源源不断的贡献者。

I re-throw if there is something that my particular class needs to do in response to an exception but the problem needs to be bubbled out to however called the method where it happened.

如果我的特定类需要做一些事情来响应异常,我会重新抛出但是问题需要冒出来然后调用它发生的方法。

I think code should be written proactively and that exceptions should be for exceptional situations, not to avoid testing for conditions.

我认为代码应该是主动编写的,异常应该是针对特殊情况,而不是为了避免测试条件。

#7


4  

I'm just on my way out but will give you a brief run down on where to use exception handling. I will attempt to address your other points when I return :)

我刚刚离开,但会简要介绍一下使用异常处理的地方。当我回来时,我会尝试解决你的其他问题:)

  1. Explicitly check for all known error conditions*
  2. 明确检查所有已知错误情况*

  3. Add a try/catch around the code if your are unsure if you were able to handle all cases
  4. 如果您不确定是否能够处理所有情况,请在代码周围添加try / catch

  5. Add a try/catch around the code if the .NET interface you are calling throws an exception
  6. 如果要调用的.NET接口抛出异常,请在代码周围添加try / catch

  7. Add a try/catch around the code if it crosses a complexity threshold for you
  8. 如果代码超过了复杂性阈值,请在代码周围添加try / catch

  9. Add a try/catch around the code if for a sanity check: You are asserting THIS SHOULD NEVER HAPPEN
  10. 如果要进行健全性检查,请在代码周围添加一个try / catch:您声明这应该永远不会发生

  11. As a general rule, I do not use exceptions as a replacement for return codes. This is fine for .NET, but not me. I do have exceptions (hehe) to this rule though, it depends on the architecture of the application your are working on as well.
  12. 作为一般规则,我不使用异常作为返回代码的替代。这对.NET来说很好,但不是我。我确实对此规则有异常(呵呵),这取决于您正在处理的应用程序的体系结构。

*Within reason. There is no need to check to see if say a cosmic ray hit your data causing a couple bits to get flipped. Understanding what is "reasonable" is an acquired skill for an engineer. It's hard to quantify, yet easy to intuit. That is, I can easily explain why I use a try/catch in any particular instance, yet I am hard pressed to imbue another with this same knowledge.

*在合理范围内。没有必要检查宇宙射线是否会击中你的数据导致一些比特被翻转。理解什么是“合理的”是工程师获得的技能。它很难量化,但很容易直观。也就是说,我可以很容易地解释为什么我在任何特定的实例中使用try / catch,但我很难用同样的知识灌输另一个。

I for one tend to steer away from heavily exception based architectures. try/catch doesn't have a performance hit as such, the hit comes in when the exception is thrown and the code might have to walk up several levels of the call stack before something handles it.

我倾向于避开基于异常的大型架构。 try / catch没有这样的性能命中,当抛出异常并且代码可能必须在处理它之前走几层调用堆栈时命中。

#8


3  

The golden rule that have tried to stick to is handle the exception as close to the source as possible.

试图坚持的黄金法则是尽可能靠近源处理异常。

If you must re-throw an exception try to add to it, re-throwing a FileNotFoundException does not help much but throwing a ConfigurationFileNotFoundException will allow it to be captured and acted upon somewhere up the chain.

如果你必须重新抛出一个异常尝试添加它,重新抛出一个FileNotFoundException并没有多大帮助,但抛出一个ConfigurationFileNotFoundException将允许它被捕获并在链的某个地方采取行动。

Another rule I try to follow is not to use try/catch as a form of program flow, so I do verify files/connections, ensure objects have been initiated, ect.. prior to using them. Try/catch should be for Exceptions, things you can not control.

我尝试遵循的另一个规则是不使用try / catch作为程序流的一种形式,所以我确实验证了文件/连接,确保对象已经启动,等等..在使用它们之前。尝试/捕获应该是例外,你无法控制的事情。

As for an empty catch block, if you are doing anything of importance in the code that generated the exception you should re-throw the exception at a minimum. If there is no consequences of the code that threw the exception not running why did you write it in the first place.

至于一个空的catch块,如果你在生成异常的代码中做了任何重要的事情,你应该至少重新抛出异常。如果没有运行异常的代码没有后果,你为什么要首先编写它。

#9


2  

Exceptions are expensive but necessary. You don't need to wrap everything in a try catch but you do need to ensure that exceptions are always caught eventually. Much of it will depend on your design.

例外情况既昂贵又必要。您不需要在try catch中包装所有内容,但确实需要确保始终捕获异常。其中很大程度上取决于您的设计。

Don't re-throw if letting the exception rise will do just as well. Never let errors pass unnoticed.

如果让异常上升同样可以做,也不要重新抛出。永远不要忽视错误。

example:

void Main()
{
  try {
    DoStuff();
  }
  catch(Exception ex) {
    LogStuff(ex.ToString());
  }

void DoStuff() {
... Stuff ...
}

If DoStuff goes wrong you'll want it to bail anyway. The exception will get thrown up to main and you'll see the train of events in the stack trace of ex.

如果DoStuff出错了,你还是希望它保释。异常将被抛到main,你会在ex的堆栈跟踪中看到一系列事件。

#10


1  

When should I re-throw an exception?

什么时候应该重新抛出异常?

Everywhere, but end user methods... like button click handlers

无处不在,但最终用户方法......就像按钮点击处理程序一样

Should I try to have a central error-handling mechanism of some kind?

我应该尝试某种*错误处理机制吗?

I write a log file... pretty easy for a WinForm app

我写了一个日志文件......对于WinForm应用来说非常简单

Do handling exceptions which might be thrown have a performance hit compared with pre-emptively testing things like whether a file on disk exists?

与先前测试诸如磁盘上的文件之类的内容相比,处理可能引发的异常会产生性能损失吗?

I'm not sure about this, but I believe it is a good practice to thow exceptions... I mean you can ask whether a file exists and if it doesn't throw a FileNotFoundException

我不确定这一点,但我认为提示异常是一个好习惯...我的意思是你可以询问文件是否存在以及它是否不会抛出FileNotFoundException

Should all executable code be enclosed in try-catch-finally blocks?

是否所有可执行代码都包含在try-catch-finally块中?

yeap

Are there any times when an empty catch block might be acceptable?

有空的挡块是否可以接受?

Yes, let's say you want to show a date, but you have no clue how that date was stores (dd/mm/yyyy, mm/dd/yyyy, etc) you try tp parse it but if it fails just keep going... if it is irrelevant to you... I would say yes, there is

是的,假设您要显示日期,但您不知道该日期是如何存储(dd / mm / yyyy,mm / dd / yyyy等),您尝试解析它但如果失败则继续...如果它与你无关......我会说是,有

#11


1  

The one thing I learned very quickly was to enclose absolutely every chunk of code that interacts with anything outside the flow of my program (i.e. File System, Database Calls, User Input) with try-catch blocks. Try-catch can incur a performance hit, but usually in these places in your code it won't be noticeable and it will pay for itself with safety.

I have used empty catch-blocks in places where the user might do something that isn't really "incorrect", but it can throw an exception...an example that comes to mind is in a GridView if the user DoubleCLicks the gray placeholder cell on the top-left it will fire the CellDoubleClick event, but the cell doesn't belong to a row. In that case, you dont really need to post a message but if you don't catch it it will throw an unhandled exception error to the user.

我很快就学到的一件事就是绝对包含与我的程序流程之外的任何东西(即文件系统,数据库调用,用户输入)交互的每一块代码和try-catch块。尝试捕获可能会导致性能损失,但通常在代码中的这些位置它不会引人注意,它将为安全带来收益。我在用户可能会做一些并非真正“不正确”的地方使用了空的catch块,但是它可以抛出一个异常...如果用户DoubleCLicks灰色占位符,我想到的一个例子是在GridView中左上角的单元格将触发CellDoubleClick事件,但该单元格不属于某一行。在这种情况下,你真的不需要发布消息,但如果你没有捕获它,它将向用户抛出未处理的异常错误。

#12


1  

When re-throwing an exception the key word throw by it self. This will throw the caught exception and still will be able to use stack trace to see where it came from.

当重新抛出异常时,关键词会自行抛出。这将抛出捕获的异常,仍然可以使用堆栈跟踪来查看它的来源。

Try
{
int a = 10 / 0;
}
catch(exception e){
//error logging
throw;
}

doing this will cause the stack trace to end in the catch statement. (avoid this)

这样做会导致堆栈跟踪在catch语句中结束。 (避免这个)

catch(Exception e)
// logging
throw e;
}

#13


1  

n my experience I've seen fit to catch exceptions when I know I'm going to be creating them. For instances when I'm in a web application and I'm doing a Response.Redirect, I know I'll be getting a System.ThreadAbortException. Since it's intentional I just have a catch for the specific type and just swallow it.

根据我的经验,当我知道我将创建它们时,我认为适合捕捉异常。对于我在Web应用程序中并且正在执行Response.Redirect的情况,我知道我将获得System.ThreadAbortException。因为它是有意的,我只是抓住特定类型并且只是吞下它。

try
{
/*Doing stuff that may cause an exception*/
Response.Redirect("http:\\www.somewhereelse.com");
}
catch (ThreadAbortException tex){/*Ignore*/}
catch (Exception ex){/*HandleException*/}

#14


1  

I deeply agree the rule of:

我非常同意以下规则:

  • Never let errors pass unnoticed.
  • 永远不要忽视错误。

The reason is that:

原因是:

  • When you first write down the code, most likely you won't have the full knowledge of 3-party code, .NET FCL lirary, or your co-workers latest contributions. In reality you cannot refuse to write code until you know every exception possiblity well. So
  • 当您第一次写下代码时,很可能您不会完全了解三方代码,.NET FCL或者您的同事最新贡献。实际上,在你完全了解每个异常可能性之前,你不能拒绝编写代码。所以

  • I constanly find that I use try/catch(Exception ex) just because I want to protected myself from unknown things, and, as you noticed, I catch Exception, not the more specific such as OutOfMemoryException etc. And, I always make the exception being popped up to me(or the QA) by ForceAssert.AlwaysAssert(false, ex.ToString() );
  • 我常常发现我使用try / catch(Exception ex)只是因为我想保护自己免受未知事物的影响,而且,正如你所注意到的,我捕获了Exception,而不是更具体的例如OutOfMemoryException等。而且,我总是做出异常通过ForceAssert.AlwaysAssert(false,ex.ToString())弹出给我(或QA);

ForceAssert.AlwaysAssert is my personal way of Trace.Assert just regardless of whether the DEBUG/TRACE macro is defined.

ForceAssert.AlwaysAssert是我个人的Trace.Assert方式,无论是否定义了DEBUG / TRACE宏。

The development cycle maybe: I noticed the ugly Assert dialog or someone else complain to me about it, then I come back to the code and figure out the reason to raise the exception and decide how to process it.

开发周期可能是:我注意到丑陋的Assert对话框或其他人向我抱怨它,然后我回到代码并找出引发异常的原因并决定如何处理它。

By this way I can write down MY code in a short time and protected me from unknown domain, but always being noticed if the abnormal things happened, by this way the system got safe and more safety.

通过这种方式,我可以在短时间内写下我的代码并保护我免受未知领域的影响,但是如果异常事件发生,总会被注意到,通过这种方式系统变得安全且更安全。

I know many of you wont agree with me because a developer should known every detail of his/her code, frankly, I'm also a purist in the old days. But nowdays I learned that the above policy is more pragmatic.

我知道很多人不同意我的看法,因为开发人员应该知道他/她的代码的每一个细节,坦率地说,我在过去也是一个纯粹主义者。但是现在我了解到上述政策更加务实。

For WinForms code, a golden rule I always obey is:

对于WinForms代码,我始终遵守的一条黄金法则是:

  • Always try/catch(Exception) your event handler code
  • 总是尝试/捕获(例外)您的事件处理程序代码

this will protected your UI being always usable.

这将保护您的UI始终可用。

For performance hit, performance penalty only happens when the code reachs catch, executing try code without the actual exception raised has no significant effect.

对于性能损失,仅在代码达到catch时执行性能损失,执行try代码而不会引发实际异常没有显着影响。

Exception should be happened with little chance, otherwise it's not exceptions.

应该以很少的机会发生异常,否则不是例外。

#15


0  

You have to think about the user. The application crash is the last thing the user wants. Therefore any operation that can fail should have a try catch block at the ui level. It's not necessary to use try catch in every method, but every time the user does something it must be able to handle generic exceptions. That by no means frees you from checking everything to prevent exceptions in the first case, but there is no complex application without bugs and the OS can easily add unexpected problems, therefore you must anticipate the unexpected and make sure if a user wants to use one operation there won't be data loss because the app crashes. There is no need to ever let your app crash, if you catch exceptions it will never be in an indeterminate state and the user is ALWAYS inconvenienced by a crash. Even if the exception is at the top most level, not crashing means the user can quickly reproduce the exception or at least record the error message and therefore greatly help you to fix the problem. Certainly a lot more than getting a simple error message and then seeing only windows error dialog or something like that.

你必须考虑用户。应用程序崩溃是用户想要的最后一件事。因此,任何可能失败的操作都应该在ui级别有一个try catch块。没有必要在每个方法中使用try catch,但每次用户执行某些操作时,它必须能够处理一般异常。这绝不会让你在第一种情况下检查所有内容以防止异常,但是没有没有错误的复杂应用程序,操作系统可以轻松添加意外问题,因此你必须预见到意外情况,并确保用户是否想要使用一个操作不会因为应用程序崩溃而导致数据丢失。没有必要让您的应用程序崩溃,如果您捕获异常,它将永远不会处于不确定状态,并且用户总是会因崩溃而感到不便。即使异常处于*别,也不会崩溃意味着用户可以快速重现异常或至少记录错误消息,因此可以帮助您解决问题。当然不仅仅是获取一个简单的错误消息,然后只看到Windows错误对话框或类似的东西。

That's why you must NEVER just be conceited and think your app has no bugs, that is not guaranteed. And it is a very small effort to wrap some try catch blocks about the appropriate code and show an error message / log the error.

这就是为什么你绝对不要只是自负,并认为你的应用没有错误,这是不能保证的。并且,对于适当的代码包装一些try catch块并显示错误消息/记录错误是一个非常小的努力。

As a user, I certainly get seriously pissed whenever a brows or office app or whatever crashes. If the exception is so high that the app can't continue it's better to display that message and tell the user what to do (restart, fix some os settings, report the bug, etc.) than to simply crash and that's it.

作为一个用户,无论什么时候眉毛或办公室应用程序或任何崩溃,我当然会非常生气。如果异常太高以至于应用程序无法继续,那么最好显示该消息并告诉用户该做什么(重新启动,修复一些操作系统设置,报告错误等),而不是简单地崩溃,就是这样。