例外とパフォーマンス
例外をスローすると、パフォーマンスに悪影響が及ぶことがあります。 定期的に失敗するコードでは、パフォーマンスの問題を最小にできるデザイン パターンを使用する必要があります。 ここでは、例外がパフォーマンスに著しく影響する可能性がある場合に有効な 2 つのデザイン パターンについて説明します。
例外がパフォーマンスに悪影響を及ぼす可能性があるため、エラー コードは使用しないでください。
パフォーマンスの問題を最小にするデザインを使用してください。 ここでは、2 つのパターンについて説明します。
一般的なシナリオで例外をスローする可能性があるメンバーに対しては、例外に関連するパフォーマンスの問題を回避するために Tester-Doer パターンの使用を検討してください。
テスター-Doer パターンは 2 つの部分に例外をスローする呼び出しをします。テスターと行為者。 Doer に例外をスローさせるような状態がないかを Tester がテストします。 このテストは、例外をスローするコードの直前に挿入され、これによって例外が防止されます。
次のコード例は、このパターンの 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 (ProcessMessage) が例外をスローする場合に、テストを行って Doer の呼び出しを防ぎます。
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 パターンを実装するには、2 つの異なるメソッドを使用して、一般的なシナリオで例外をスローする可能性がある操作を実行します。 1 つは X メソッドで、操作を実行し、必要に応じて例外をスローします。 もう 1 つは TryX メソッドで、例外はスローしませんが、代わりに成功または失敗を示す Boolean 値を返します。 TryX の呼び出しが成功したときに返されるデータは、out (Visual Basic の場合は ByRef) パラメーターを使用して返されます。 Parse メソッドと TryParse メソッドは、このパターンの例です。
TryParse パターンを使用する各メンバーに例外スロー メンバーを提供してください。
TryX メソッドを使用する場合は、out パラメーターについて理解する必要があるため、このメソッドのみを提供することはほとんどの場合正しいデザインとは言えません。 また、一般的なシナリオでは、パフォーマンスへの例外の影響は問題になりません。一般的なシナリオでは、使いやすいメソッドを提供する必要があります。
Portions Copyright 2005 Microsoft Corporation. All rights reserved.
Portions Copyright Addison-Wesley Corporation. All rights reserved.
設計ガイドラインの詳細についてを参照してください、「フレームワークの設計ガイドライン。規則、慣用句、および再利用可能なパターン。ネット ライブラリ」本クシシュトフ Cwalina、ブラッド エイブラムス、アスキー、2005 年発表しました。