异常和性能

引发异常可能会对性能造成不良的影响。 对于经常性执行失败的代码,可以使用设计模式最大限度地减少性能问题。 本主题描述两种设计模式,在异常可能会严重影响性能时使用这两种模式很有帮助。

不要由于担心异常可能会对性能造成不良影响而使用错误代码。

利用设计来减少性能问题。 在本主题中描述了两种设计模式。

对于可能在常见方案中引发异常的成员,可以考虑使用 Tester-Doer 模式来避免与异常相关的性能问题。

Tester-doer 模式将分为了调用,可能会引发异常,分成两个部分: 一种测试仪和实干家。 Tester 对可能导致 Doer 引发异常的状态执行测试。 测试恰好插入在引发异常的代码之前,从而防范异常发生。

下面的代码示例演示此模式的 Doer 部分。 该示例包含一个方法,在向该方法传递 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 Doer
{
    // Method that can potential throw exceptions often.
    public static void ProcessMessage(string message)
    {
        if (message == null)
        {
            throw new ArgumentNullException("message");
        }
    }
    // Other methods...
}
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...
};

下面的代码示例演示此模式的 Tester 部分。 该方法利用一个测试来避免在 Doer 将引发异常时调用 Doer (ProcessMessage)。

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 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 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);
            }
        }
    }
};

注意,当在测试涉及可变对象的多线程应用程序中使用该模式时,必须解决可能出现的争用状态问题。 线程可以在测试之后且 Doer 执行之前更改可变对象的状态。 使用线程同步技术可以解决这些问题。

对于可能在常见方案中引发异常的成员,可以考虑使用 TryParse 模式来避免与异常相关的性能问题。

若要实现 TryParse 模式,需要为执行可在常见方案中引发异常的操作提供两种不同的方法。 第一种方法 X, 执行该操作并在适当时引发异常。 第二种方法 TryX, 不引发异常,而是返回一个 Boolean 值以指示成功还是失败。 由对 TryX 的成功调用所返回的任何数据都通过使用 out(在 Visual Basic 中为 ByRef)参数予以返回。 ParseTryParse 方法就是此模式的示例。

为每个使用 TryParse 模式的成员提供一个引发异常的成员。

只提供 TryX 方法几乎在任何时候都不是正确的设计,因为使用该方法需要了解 out 参数。 此外,对于大多数常见方案来说,异常对性能的影响不会构成问题;因此应在大多数常见方案中提供易于使用的方法。

部分版权所有 2005 Microsoft Corporation。 保留所有权利。

部分版权所有 Addison-Wesley Corporation。 保留所有权利。

设计指引的详细信息,请参阅"框架设计准则: 公约、 成语和可重复使用的模式。网络图书馆"书 Krzysztof Cwalina 和布拉德 · 艾布拉姆斯,2005年艾迪生 - 韦斯利,发表。

请参见

其他资源

类库开发的设计准则

异常设计准则