我需要翻译来自Task<T>
的异常,其方式与对正常同步代码执行以下操作相同:
try {
client.Call();
} catch(FaultException ex) {
if (ex.<Some check>)
throw new Exception("translated");
}
但是,我想以异步方式执行此操作,即上面的Call
实际上是Task CallAsync()
。
所以在C#5中,我的方法看起来像这样:
async Task CallAndTranslate()
{
try{
await client.CallAsync();
} catch(FaultException ex) {
if (ex.FaultCode ...)
throw new Exception("translated");
}
}
但我现在正在使用C#4。
所以我能做什么,因为我想要触发一个任务,但是要翻译(TPL)错误,然后再将整个事件公开为Task<T>
?
编辑:一种更具体的说法:
public class TranslatingExceptions
{
public Task ApiAsync() // The inner layer exposes it exactly this way
{
return Task.Factory.StartNew(()=>{ throw new Exception( "Argument Null" );});
}
public Task WrapsApiAsync() // this layer needs to expose it exactly this way
{
// async preview pseudocode for what I need to do
try {
await ApiAsync( );
} catch (Exception exception){
if( exception.Message == "Argument Null" )
throw new ArgumentNullException();
}
}
[Fact]
public void Works()
{
var exception = Record.Exception( () =>
WrapsApiAsync().Wait());
Assert.IsType<ArgumentNullException>( exception.InnerException);
}
}
如果不需要C#5,您将如何实施WrapsApiAsync()
?
答案 0 :(得分:1)
好的,现在我已经完全明白你在寻找什么了,这就是你需要做的就是在4.0中构建等价物:
public class TranslatingExceptions
{
public Task ApiAsync() // The inner layer exposes it exactly this way
{
return Task.Factory.StartNew(()=>{ throw new Exception( "Argument Null" );});
}
public Task WrapsApiAsync() // this layer needs to expose it exactly this way
{
// Grab the task that performs the "original" work
Task apiAsyncTask = ApiAsync();
// Hook a continuation to that task that will do the exception "translation"
Task result = aspiAsync.ContinueWith(antecedent =>
{
// Check if the antecedent faulted, if so check what the exception's message was
if ( antecedent.IsFaulted
&& antecedent.Exception.InnerException.Message == "Argument Null" )
{
throw new ArgumentNullException();
}
},
TaskContinuationOptions.ExecuteSynchronously);
// Now we return the continuation Task from the wrapper method so that the caller of the wrapper method waits on that
return result;
}
[Fact]
public void Works()
{
var exception = Record.Exception(() =>
WrapsApiAsync().Wait());
Assert.IsType<ArgumentNullException>(exception.InnerException);
}
}
这应该可以实现您的目标。需要注意的一点是,在创建延续时我使用TaskContinuationOptions.ExecuteSynchronously
。这是因为这项工作很小而且很紧,你不想让调度程序等待从线程池中拾取整个其他线程只是为了进行这项检查。