处理异常时.Net中常见的编程错误?

jCo*_*son 38 .net c# vb.net exception-handling

您在处理异常时遇到的一些最常见的错误是什么?

看起来异常处理可能是学习如何在.Net中做"正确"的最困难的事情之一.特别是考虑到目前排名第一的常见编程错误,.NET开发人员要避免错误?与异常处理有关.

希望通过列出一些最常见的错误,我们都可以学会更好地处理异常.

Eri*_*ert 44

您在处理异常时遇到的一些最常见的错误是什么?

我能想到很多.

首先阅读我关于将异常分类为烦恼,愚蠢,致命外生的文章:

http://ericlippert.com/2008/09/10/vexing-exceptions/

一些常见错误:

  • 未能处理外部异常.
  • 未能处理棘手的异常.
  • 构建抛出烦恼异常的方法.
  • 处理您实际无法处理的异常,例如致命异常.
  • 处理隐藏代码中的错误的异常; 不处理一个骨头异常,修复bug,使其不会被抛出

  • 安全错误:未安全模式失败

    try
    {
      result = CheckPassword();
      if (result == BadPassword) throw BadPasswordException();
    }
    catch(BadPasswordException ex) { ReportError(ex); return; }
    catch(Exception ex) { LogException(ex); }
    AccessUserData();
    
    Run Code Online (Sandbox Code Playgroud)

    看看发生了什么?我们未能进入不安全模式.如果CheckPassword抛出NetworkDriverIsAllMessedUpException,那么无论密码是否正确,我们都会捕获它,记录它并访问用户的数据.未能达到安全模式; 当你得到任何例外时,假设最坏的情况.

  • 安全错误:产生直接或间接泄漏敏感信息的异常.

    这并不完全是关于处理代码中的异常,而是关于生成由恶意代码处理的异常.

    好笑的故事.在.NET 1.0发送给客户之前,我们发现了一个错误,可以调用一个引发异常的方法"调用此方法的程序集没有权限来确定文件C:\ foo.txt的名称".大.谢谢你让我知道.什么阻止所述程序集捕获异常并询问其消息以获取文件名?没有.我们在发货前修好了.

    这是一个直接的问题.间接问题是我LoadPicture在VBScript中实现的问题.它给出了不同的错误消息,具体取决于不正确的参数是目录,不是图片的文件还是不存在的文件.这意味着您可以将它用作非常慢的磁盘浏览器!通过尝试一大堆不同的东西,你可以逐步建立一个人的硬盘上的文件和目录的图片.应该设计例外,以便如果它们由不可靠的代码处理,那么该代码就不会从用于引发异常的任何内容中获取用户的私有信息.(LoadPicture现在提供的帮助错误信息要少得多.)

  • 安全性和资源管理错误:不清理资源的处理程序是等待发生的资源泄漏.资源泄漏可被用作恶意部分信任代码的拒绝服务攻击,该代码故意产生异常产生的情况.

  • 稳健性错误:除非处理特定的外部异常,否则处理程序必须假定程序状态混乱.对于最后的块,尤其如此.当你处理一个意外的异常时,它完全有可能,甚至可能在你的程序中出现了一些问题.您不知道您的子系统是否正在工作,如果它们是,那么调用它们是否会使情况变得更好或更糟.集中精力记录错误并尽可能保存用户数据,并尽可能干净地关闭.假设一切正常.

  • 安全性错误:任何可能存在恶意的代码可以运行之前,需要撤消具有安全性影响的临时全局状态突变 .恶意代码可以最终块运行之前运行!有关详细信息,请参阅我的文章:

http://blogs.msdn.com/ericlippert/archive/2004/09/01/224064.aspx


Ada*_*ear 25

重新抛出这样的异常:

try 
{ 
   // some code here
}
catch(Exception ex)
{
   // logging, etc
   throw ex;
}
Run Code Online (Sandbox Code Playgroud)

这会导致堆栈跟踪死亡,使得它的可用性大大降低.重新抛出的正确方法是这样的:

try 
{ 
   // some code here
}
catch(Exception ex)
{
   // logging, etc
   throw;
}
Run Code Online (Sandbox Code Playgroud)

  • @BlueRaja:我实际上没有点击链接.呃,好吧.在这里提到它不会有害,因为它仍然与这个问题有关. (3认同)
  • "正确的方式"有点极端; 有一些'throw ex`的有效案例. (2认同)
  • @Dour:`throw ex;`在你的情况下是无效的.`throw new SaferException(...)`就是你想要的. (2认同)

Jay*_*ggs 12

在许多情况下捕获所有异常时,您应该尝试捕获特定的异常:

try {
  // Do something.
} catch (Exception exc) {
  // Do something.
}
Run Code Online (Sandbox Code Playgroud)

而不是:

try {
  // Do something.
} catch (IOException exc) {
  // Do something.
}
Run Code Online (Sandbox Code Playgroud)

应从最具体到最不重要的例外订购.


CAR*_*OTH 10

用无意义的信息重新抛出异常.

try
{
    ...
}
catch (Exception ex)
{
   throw new Exception("An error ocurred when saving database changes").
}
Run Code Online (Sandbox Code Playgroud)

你不会相信我经常在生产中看到这样的代码.

  • 如果原始异常包含有关服务器实现细节的敏感信息,并且将处理异常的调用者不受信任,则这通常是一个好主意.例如,试图对数据库进行SQL注入攻击的攻击者会喜欢看到详细的错误消息,该错误消息准确描述了查询是如何出错的. (21认同)

Sri*_*ddi 9

没人在谈论看到像这样的空挡块....

 try{  
      //do something
    }
catch(SQLException sqex){  
        // do nothing  
    }
Run Code Online (Sandbox Code Playgroud)

也永远不要使用异常处理来创建备用方法流程......

 try{  
     //do something  

 }catch(SQLException sqex){  

     //do something else  
 }
Run Code Online (Sandbox Code Playgroud)

  • 不使用控制流异常的+1. (4认同)

Blu*_*eft 7

不使用usingIDisposable对象:

File myFile = File.Open("some file");
callSomeMethodWhichThrowsException(myFile);
myFile.Close();
Run Code Online (Sandbox Code Playgroud)

myFile不会被关闭,直到调用myFile的终结器(可能永远不会),因为在myFile.Close()调用之前抛出了异常.

正确的方法是

using(File myFile = File.Open("some file"))
{
    callSomeMethodWhichThrowsException(myFile);
}
Run Code Online (Sandbox Code Playgroud)

这会被编译器翻译成类似的东西:

File myFile = File.Open("some file");
try
{
    callSomeMethodWhichThrowsException(myFile);
}
finally
{
    if(myFile != null)
        myFile.Dispose(); //Dispose() calls Close()
}
Run Code Online (Sandbox Code Playgroud)

因此,即使面对异常,文件也会关闭.


CAR*_*OTH 6

忘记重新抛出catched异常时忘记设置内部异常

try
{
    ...
}
catch (IOException ioException)
{
    throw new AppSpecificException("It was not possible to save exportation file.")
    // instead of
    throw new AppSpecificException("It was not possible to save exportation file.", ioException);
}
Run Code Online (Sandbox Code Playgroud)

当我发布这个答案时,我忘记提到我们应该始终考虑何时包含内部异常,因为安全原因.正如Eric Lippert本主题的另一个答案中指出的那样,一些例外可以提供有关服务器实现细节的敏感信息.因此,如果将处理将处理异常的调用者不受信任,则包含内部异常信息不是一个好主意.