代码改变世界

[FxCop.设计规则]12. 不要捕获所有异常

2005-06-20 19:14  Colin Han  阅读(2552)  评论(2编辑  收藏  举报

12.     不要捕获所有异常

翻译概述:

在传统的C++中,对于大多数错误逻辑使用返回错误码的方式来定义。从而使程序逻辑中充斥了大量的条件判断逻辑,严重的影响了代码的可维护性和美观。而异常机制为开发提供了一套相对独立和易管理的错误处理方式,因此,在目前的大多数程序设计语言中都提供了对异常的支持,包括C++

但是,异常属于一个脱离程序逻辑之外的控制流程,因此,对异常的滥用很多时候反而会降低程序逻辑的可维护性和易读性。(相信大多数老程序员都有过在修Bug时毫无原则的添加异常捕获逻辑的经历)而FxCop中的这条规则就实现了对异常捕获滥用的检查。

原文引用:

Do not catch general exception types

TypeName:

DoNotCatchGeneralExceptionTypes

CheckId:

CA1031

Category:

Microsoft.Design

Message Level:

CriticalError

Certainty:

95%

Breaking Change:

NonBreaking


Cause: System.Exception or System.SystemException is caught in a catch statement, or a general catch clause is used.

Rule Description

General exceptions should not be caught.

How to Fix Violations

To fix a violation of this rule, catch a more specific exception, or re-throw the general exception as the last statement in the catch block.

When to Exclude Messages

Do not exclude a message from this rule. Catching general exception types can hide run-time problems from the library user, and can complicate debugging.

Example Code

The following example shows a type that violates this rule and a type that correctly implements the catch block.

[C#]

using System;
using System.IO;
 
namespace DesignLibrary
{
    
// Creates two violations of the rule.
    public class GenericExceptionsCaught
    
{
        FileStream inStream;
        FileStream outStream;
 
        
public GenericExceptionsCaught(string inFile, string outFile)
        
{
            
try
            
{
                inStream 
= File.Open(inFile, FileMode.Open);
            }

            
catch(SystemException e)
            
{
                Console.WriteLine(
"Unable to open {0}.", inFile);
            }

 
            
try
            
{
                outStream 
= File.Open(outFile, FileMode.Open);
            }

            
catch
            
{
                Console.WriteLine(
"Unable to open {0}.", outFile);
            }

        }

    }

 
    
public class GenericExceptionsCaughtFixed
    
{
        FileStream inStream;
        FileStream outStream;
 
        
public GenericExceptionsCaughtFixed(string inFile, string outFile)
        
{
            
try
            
{
                inStream 
= File.Open(inFile, FileMode.Open);
            }

 
            
// Fix the first violation by catching a specific exception.
            catch(FileNotFoundException e)
            
{
                Console.WriteLine(
"Unable to open {0}.", inFile);
            }

 
            
try
            
{
                outStream 
= File.Open(outFile, FileMode.Open);
            }

 
            
// Fix the second violation by re-throwing the generic 
            
// exception at the end of the catch block.
            catch
            
{
                Console.WriteLine(
"Unable to open {0}.", outFile);
                
throw;
            }

        }

    }

}


[Visual Basic]
 

Imports System

Imports System.IO

 

Namespace DesignLibrary

 

    ' Creates two violations of the rule.

    Public Class GenericExceptionsCaught

 

        Dim inStream  As FileStream

        Dim outStream As FileStream

 

        Sub New(inFile As String, outFile As String)

 

            Try

                inStream = File.Open(inFile, FileMode.Open)

            Catch ex As SystemException

                Console.WriteLine("Unable to open {0}.", inFile)

            End Try

 

            Try

                outStream = File.Open(outFile, FileMode.Open)

            Catch

                Console.WriteLine("Unable to open {0}.", outFile)

            End Try

 

        End Sub

 

    End Class

 

    Public Class GenericExceptionsCaughtFixed

 

        Dim inStream  As FileStream

        Dim outStream As FileStream

 

        Sub New(inFile As String, outFile As String)

 

            Try

                inStream = File.Open(inFile, FileMode.Open)

 

            ' Fix the first violation by catching a specific exception.

            Catch ex As FileNotFoundException

                Console.WriteLine("Unable to open {0}.", inFile)

            End Try

 

            Try

                outStream = File.Open(outFile, FileMode.Open)

 

            ' Fix the second violation by re-throwing the generic

            ' exception at the end of the catch block.

            Catch

                Console.WriteLine("Unable to open {0}.", inFile)

            Throw

            End Try

 

        End Sub

 

    End Class

 

End Namespace


[C++]

#using <mscorlib.dll>
using namespace System;
using namespace System::IO;
 
namespace DesignLibrary
{
    
// Creates two violations of the rule.
    public __gc class GenericExceptionsCaught
    
{
        FileStream
* inStream;
        FileStream
* outStream;
 
    
public:
        GenericExceptionsCaught(String
* inFile, String* outFile)
        
{
            
try
            
{
                inStream 
= File::Open(inFile, FileMode::Open);
            }

            
catch(SystemException* e)
            
{
                Console::WriteLine(S
"Unable to open {0}.", inFile);
            }

 
            
try
            
{
                outStream 
= File::Open(outFile, FileMode::Open);
            }

            
catch(Exception* e)
            
{
                Console::WriteLine(S
"Unable to open {0}.", outFile);
            }

        }

    }
;
 
    
public __gc class GenericExceptionsCaughtFixed
    
{
        FileStream
* inStream;
        FileStream
* outStream;
 
    
public:
        GenericExceptionsCaughtFixed(String
* inFile, String* outFile)
        
{
            
try
            
{
                inStream 
= File::Open(inFile, FileMode::Open);
            }

 
            
// Fix the first violation by catching a specific exception.
            catch(FileNotFoundException* e)
            
{
                Console::WriteLine(S
"Unable to open {0}.", inFile);
            }

 
            
try
            
{
                outStream 
= File::Open(outFile, FileMode::Open);
            }

 
            
// Fix the second violation by re-throwing the generic 
            
// exception at the end of the catch block.
            catch(Exception* e)
            
{
                Console::WriteLine(S
"Unable to open {0}.", outFile);
                
throw;
            }

        }

    }
;
}


Related Rules

Rethrow to preserve stack details

See Also

Error Raising and Handling Guidelines

引起的原因:

使用catch语句捕获System.ExceptionSystem.SystemException类型的异常,或者使用了无类型catch子句。

 

描述:

不应该捕获所有的异常。

修复:

只捕获部分指定类型的异常,或者在catch语句块的结尾将一半类型的异常重新抛出。

例外:

不要禁用这条规则。捕获所有的异常将会隐藏运行时的一些问题,这样将会使用户调试程序变得复杂。

 

例程:

原文的例子中,分别用三种语言分别演示错误的用法和如何修复这个错误。

其中,类型GenericExceptionsCaught在构造函数中有两段捕获异常的代码,第一段捕获了System.SystemException类型的异常,第二段捕获了所有的异常。

而类型GenericExceptionsCaughtFixed中,演示了如何修正这两段不正确的逻辑,对于第一段逻辑,使用了一个特定类型的异常捕获语句代替捕获SystemException。第二段逻辑将异常重新抛出。