当某个成员无法成功执行它应执行的操作时,将会引发异常。 这称为“执行失败”。 例如,如果 Connect 方法无法连接到指定的远程终结点,则这就是一个执行故障,将有一个异常被引发。
下列准则可帮助确保在适当时引发异常。
不要返回错误代码。 异常是报告框架中的错误的主要手段。
异常设计准则 讨论了使用异常的许多好处。
通过引发异常来报告执行故障。 如果某一成员无法按预期方式成功执行,则应将这种情况视为一个执行故障并引发一个异常。
如果代码遇到继续执行则不安全的情况,应考虑通过调用 System.Environment.FailFast(System.String)(.NET Framework 2.0 中的一种功能)来终止进程,而不是引发异常。
尽可能不对正常控制流使用异常。 除了系统故障及可能导致争用状态的操作之外,框架设计人员还应设计一些 API 以便用户可以编写不引发异常的代码。 例如,可以提供一种在调用成员之前检查前提条件的方法,以便用户可以编写不引发异常的代码。
下面的代码示例演示如何进行测试以防止在消息字符串为 null(在 Visual Basic 中为 Nothing)时引发异常。
Public Class Doer
' Method that can potential throw exceptions often.
Public Shared Sub ProcessMessage(ByVal message As String)
If (message = Nothing) Then
Throw New ArgumentNullException("message")
End If
End Sub
' Other methods...
End Class
Public Class Tester
Public Shared Sub TesterDoer(ByVal messages As ICollection(Of String))
For Each message As String In messages
' Test to ensure that the call
' won't cause the exception.
If (Not (message) Is Nothing) Then
Doer.ProcessMessage(message)
End If
Next
End Sub
End Class
public class Doer
{
// Method that can potential throw exceptions often.
public static void ProcessMessage(string message)
{
if (message == null)
{
throw new ArgumentNullException("message");
}
}
// Other methods...
}
public class Tester
{
public static void TesterDoer(ICollection<string> messages)
{
foreach (string message in messages)
{
// Test to ensure that the call
// won't cause the exception.
if (message != null)
{
Doer.ProcessMessage(message);
}
}
}
}
public ref class Doer
{
public:
// Method that can potential throw exceptions often.
static void ProcessMessage(String^ message)
{
if (message == nullptr)
{
throw gcnew ArgumentNullException("message");
}
}
// Other methods...
};
public ref class Tester
{
public:
static void TesterDoer(ICollection<String^>^ messages)
{
for each (String^ message in messages)
{
// Test to ensure that the call
// won't cause the exception.
if (message != nullptr)
{
Doer::ProcessMessage(message);
}
}
}
};
有关可以减少异常引发数量的设计方案的其他信息,请参见 异常和性能。
考虑引发异常的性能影响。
记录公共可调用的成员因成员协定冲突(而不是系统故障)而引发的所有异常,并将这些异常视为协定的一部分。 包含在协定中的异常不应从一个版本更改到下一个版本。
不要包含可以根据某一选项引发或不引发异常的公共成员。
例如,不要定义如下所示的成员:
Private Function ParseUri(ByVal uriValue As String, ByVal throwOnError As Boolean) As Uri
Uri ParseUri(string uriValue, bool throwOnError)
Uri^ ParseUri(String^ uriValue, bool throwOnError)
不要包含将异常作为返回值或输出参数返回的公共成员。
此项准则适用于公共可见的成员。 使用私有帮助器方法构造和初始化异常是可以接受的。
考虑使用异常生成器方法。 从不同的位置引发同一异常会经常发生。 为了避免代码膨胀,请使用帮助器方法创建异常并初始化其属性。
帮助器方法不得引发异常,否则堆栈跟踪将无法正确反映出引发异常的调用堆栈。
不要从异常筛选器块中引发异常。 当异常筛选器引发异常时,公共语言运行时 (CLR) 将捕获该异常,然后该筛选器返回 false。 此行为与筛选器显式执行和返回 false 的行为无法区分,因此很难调试。
有些语言(如 C#)不支持异常筛选器。
避免从 finally 块中显式引发异常。 可以接受因调用引发异常的方法而隐式引发的异常。
部分版权所有 2005 Microsoft Corporation。 保留所有权利。
部分版权所有 Addison-Wesley Corporation。 保留所有权利。
设计指引的详细信息,请参阅"框架设计准则: 公约、 成语和可重复使用的模式。网络图书馆"书 Krzysztof Cwalina 和布拉德 · 艾布拉姆斯,2005年艾迪生 - 韦斯利,发表。