Share via


Exception Throwing

Exceptions are thrown when a member cannot successfully do what it is designed to do. This is known as execution failure. For example, if the Connect method cannot connect to the specified remote end point, this is an execution failure and an exception is thrown.

The following guidelines help ensure that you throw exceptions when appropriate.

Do not return error codes. Exceptions are the primary means of reporting errors in frameworks.

Design Guidelines for Exceptions discusses many of the benefits you get by using exceptions.

Do report execution failures by throwing exceptions. If a member cannot successfully do what it is designed to do, that should be considered an execution failure and an exception should be thrown.

Consider terminating the process by calling System.Environment.FailFast(System.String) (a .NET Framework version 2.0 feature) instead of throwing an exception, if your code encounters a situation where it is unsafe to continue executing.

Do not use exceptions for normal flow of control, if possible. Except for system failures and operations with potential race conditions, framework designers should design APIs so that users can write code that does not throw exceptions. For example, you can provide a way to check preconditions before calling a member so that users can write code that does not throw exceptions.

The following code example demonstrates testing to prevent exceptions from being thrown when a message string is null (Nothing in Visual Basic).

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

For additional information about design patterns that can reduce the number of exceptions thrown, see the Exceptions and Performance.

Consider the performance implications of throwing exceptions.

Do document all exceptions thrown by publicly callable members because of a violation of the member contract (rather than a system failure) and treat them as part of your contract. Exceptions that are a part of the contract should not change from one version to the next.

Do not have public members that can either throw or not throw exceptions based on some option.

For example, do not define members such as the following:

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)

Do not have public members that return exceptions as the return value or as an out parameter.

This guideline is for publicly visible members. It is acceptable to use a private helper method to construct and initialize exceptions.

Consider using exception builder methods. It is common to throw the same exception from different places. To avoid code bloat, use helper methods that create exceptions and initialize their properties.

The helper method must not throw the exception or the stack trace will not accurately reflect the call stack that caused the exception.

Do not throw exceptions from exception filter blocks. When an exception filter raises an exception, the exception is caught by the common language runtime (CLR), and the filter returns false. This behavior is indistinguishable from the filter executing and returning false explicitly and is therefore very difficult to debug.

Some languages such as C# do not support exception filters.

Avoid explicitly throwing exceptions from finally blocks. Implicitly thrown exceptions resulting from calling methods that throw are acceptable.

Portions Copyright 2005 Microsoft Corporation. All rights reserved.

Portions Copyright Addison-Wesley Corporation. All rights reserved.

For more information on design guidelines, see the "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" book by Krzysztof Cwalina and Brad Abrams, published by Addison-Wesley, 2005.

See Also

Concepts

Choosing the Right Type of Exception to Throw

Other Resources

Design Guidelines for Developing Class Libraries

Design Guidelines for Exceptions