异步TryParse(...)模式

时间:2016-06-14 11:25:51

标签: c# async-await

.NET BCL中有很多常见的bool TryXXX(out T result)方法,最受欢迎的方法可能是int.TryParse(...)

我想实现异步 TryXXX()方法。显然,我无法使用out参数。

这是否有既定的模式?

更重要的是,我需要下载并解析一个文件。该文件可能不存在。

这是我到目前为止所提出的:

public async Task<DownloadResult> TryDownloadAndParse(string fileUri)
{
    try
    {
        result = await DownloadAndParse(fileUri); //defined elsewhere
        return new DownloadResult {IsFound = true, Value = result}
    }
    catch (DownloadNotFoundException ex)
    {
        return new DownloadResult {IsFound = false, Value = null}
    }
    //let any other exception pass
}

public struct DownloadResult
{
    public bool IsFound { get; set; }

    public ParsedFile Value { get; set; }
}

2 个答案:

答案 0 :(得分:3)

我提出了以下定义。 defaultValue参数主要是为了能够重载TryGet方法,因为泛型约束不是方法签名的一部分,这使得该方法在决定调用哪个方法时是唯一的(例如,返回类型也不是签名的一部分)。

public async Task<T> TryGet<T>(Func<Task<T>> func, T defaultValue = null) where T : class
{
    try
    {
        return await func();
    }
    catch (ArgumentException)
    {
        return defaultValue;
    }
    catch (FormatException)
    {
        return defaultValue;
    }
    catch (OverflowException)
    {
        return defaultValue;
    }
}

public async Task<Nullable<T>> TryGet<T>(Func<Task<T>> func, Nullable<T> defaultValue = null) where T : struct
{
    try
    {
        return await func();
    }
    catch (ArgumentException)
    {
        return defaultValue;
    }
    catch (FormatException)
    {
        return defaultValue;
    }
    catch (OverflowException)
    {
        return defaultValue;
    }
}

您应该检查异常处理,此示例处理常见的解析异常。对其他异常做出反应可能更有意义,例如InvalidOperationExceptionNotSupportedException,可能是框架本身最常用的异常类型(不一定是最常抛出的异常类型)。

另一种方法是重新抛出关键异常,例如ThreadAbortException,并有一个返回默认值的简单catch-all子句。但是,无论多么严重,这都会隐藏每一个不被视为关键的例外。

因此,并且因为抛出异常是一项昂贵的操作,它的Parse通常是根据TryParse来定义的。因此,TryGet应该签订合同,例如:处理OperationCanceledException,其中包含TaskCanceledException,而不包含任何内容。

最后,您应该按照Async-suffix约定将其命名为TryGetAsync [1] [2]

答案 1 :(得分:1)

可能的决定之一是ParsedFile数组,包含0或1个元素。

public async Task<ParsedFile[]> TryDownloadAndParse(string fileUri)
{
    try
    {
        return new[] { await DownloadAndParse(fileUri) };
    }
    catch (DownloadNotFoundException ex)
    {
        return new ParsedFile[0];
    }
}

现在您可以检查结果:

. . .

var parsedFiles = await TryDownloadAndParse(url);
if (parsedFiles.Any())
{
    var parsedFile = parsedFiles.Single();
    // more processing
}

. . .

如果您想调用void方法,可以使用?.运算符:

var parsedFiles = await TryDownloadAndParse(url);
parsedFiles.SingleOrDefault()?.DoVeryImportantWorkWithoutResult();

<强>更新

在Azure中,您可以使用ConditionalValue<TValue> class

相关问题