Search code examples
c#.netasynchronousdocumentation

How to document exceptions of async methods?


A sample method with XML documentation:

// summary and param tags are here when you're not looking.
/// <exception cref="ArgumentNullException>
///    <paramref name="text" /> is null.
/// </exception>
public void Write(string text)
{
    if (text == null)
        throw new ArgumentNullException("text", "Text must not be null.");

    // sync stuff...
}

Write(null) throws an exception as expected. Here is an asynchronous method:

public async Task WriteAsync(string text)
{
    if (text == null)
        throw new ArgumentNullException("text", "Text must not be null.");

    // async stuff...
}

WriteAsync(null), won't throw an exception until awaited. Should I specify the ArgumentNullException in an exception tag anyway? I think it would make the consumer think that calling WriteAsync may throw an ArgumentNullException and write something like this:

Task t;
try
{
    t = foo.WriteAsync(text);
}
catch (ArgumentNullException)
{
    // handling stuff.
}

What is the best practice for documenting exceptions in asynchronous methods?


Solution

  • Not a direct answer, but personally I'd advise leaning towards fast-fail here; this might mean writing 2 methods:

    public Task WriteAsync(string text) // no "async"
    {
        // validation
        if (text == null)
            throw new ArgumentNullException("text", "Text must not be null.");
    
        return WriteAsyncImpl(text);
    }
    private async Task WriteAsyncImpl(string text)
    {
        // async stuff...
    }
    

    This pattern is also an ideal place to add "fast path" code, for example:

    public Task WriteAsync(string text) // no "async"
    {
        // validation
        if (text == null)
            throw new ArgumentNullException("text", "Text must not be null.");
    
        if (some condition)
            return Task.FromResult(0); // or similar; also returning a pre-existing
                                       // Task instance can be useful
    
        return WriteAsyncImpl(text);
    }