简体   繁体   中英

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?

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

Microsoft doesn't seem to differentiate between the async method throwing an exception and the returned Task having an exception stored in its Exception property. Eg:

WebClient.DownloadFileTaskAsync(string, string)

Personally, I would choose to document the exceptions as part of the documentation for the return value (ie the returned Task ), since the distinction may be important for clients.

I'd advise to keep the exception tags since they show up in Intellisense.

Striving for conciseness, I'd not mention whether an exception is fast failing or not, as long as this follows intuition. That is, a sanity check should fail fast, while failure during execution should not. If you must diverge from this rule, please document it.

Please be aware that changing whether the exception is thrown synchronously (fail fast) or when awaited might break customer code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM