.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; }
}
答案 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;
}
}
您应该检查异常处理,此示例处理常见的解析异常。对其他异常做出反应可能更有意义,例如InvalidOperationException
和NotSupportedException
,可能是框架本身最常用的异常类型(不一定是最常抛出的异常类型)。
另一种方法是重新抛出关键异常,例如ThreadAbortException
,并有一个返回默认值的简单catch-all子句。但是,无论多么严重,这都会隐藏每一个不被视为关键的例外。
因此,并且因为抛出异常是一项昂贵的操作,它的Parse
通常是根据TryParse
来定义的。因此,TryGet
应该签订合同,例如:处理OperationCanceledException
,其中包含TaskCanceledException
,而不包含任何内容。
答案 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。