在匿名回调中捕获异常
Catching exceptions in anonymous callback
我不确定为什么这不起作用。我怀疑这与单独的工作线程有关。我还没有找到任何关于以这种方式捕获异常的工作。
我想我可以创建一个 Task 对象,然后 运行 但我更愿意保留此架构,因为其中包含的代码非常复杂。
public void MethodOne(){
try{
MethodTwo(response =>{
//Do something with the response
});
}
catch(Exception error){
//This never executes when method two throws exception
}
}
public void MethodTwo(Action<Object> callback){
//Conduct async call to external server
AppServer.MakeCall( response =>{
if(response.IsValid)
callback(response.Object);
else
throw new FooException();
});
}
因为这个程序是异步的,回调甚至在 MethodTwo
返回很久之后才被调用并且该线程继续离开 try
块并做更大更好的事情.在可能遥远的未来的某个时刻,另一个线程正在调用回调。
正如您自己提到的,一种可能性是使用 Task
而不是使用回调。 TPL 的主要优点之一是它处理错误的方式。如果异步方法 returns a Task
,您不仅可以使用 ContinueWith
(或 await
)添加回调,还可以处理这些延续中的错误。
使用回调处理此问题的方法是接受两个回调,一个在响应有效时调用,另一个在有 exception/error 时调用。对于调用者来说,它不像使用 try/catch
那样漂亮,但它是您在基于回调的模型中可以做的最好的事情。
Servy说得对。因为它已经是异步的,所以可能不需要使用另一个线程或任务。但是您可以为此使用 TaskCompletionSource 。
public void MethodOne()
{
MethodTwo()
.ContinueWith(task =>
{
if (task.IsFaulted)
// Handle error in task.Exception
;
else
{
object obj = task.Result;
// Handle object
}
});
}
public Task<object> MethodTwo()
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
//Conduct async call to external server
AppServer.MakeCall(response =>
{
if (Response.IsValid)
tcs.TrySetResult(response.Object);
else
tcs.TrySetException(new FooException());
});
return tcs.Task;
}
您还可以在 MethodTwo lambda 参数中执行 try/catch and/or 使用完整的 Response 对象而不是仅响应数据对象实例。`
public void MethodOne()
{
MethodTwo(response =>
{
if (Response.IsValid)
callback(Response.Object);
else
throw new FooException(); // Or error handling directly
});
}
public void MethodTwo(Action<Response> callback)
{
//Conduct async call to external server
AppServer.MakeCall(response =>
{
callback(response);
});
}
如果不允许从 MethodOne 引用 Response 对象,and/or 不允许更改回调签名,那么您可以使用 FooException 作为参数调用回调操作 callback(new FooException);
public void MethodOne()
{
MethodTwo(response =>
{
if (response is FooException)
{
FooException exc = response as FooException;
}
else
{
// Handle response;
}
});
}
public void MethodTwo(Action<object> callback)
{
//Conduct async call to external server
AppServer.MakeCall(response =>
{
if (Response.IsValid)
callback(Response.Object);
else
callback(new FooException());
});
}
我不确定为什么这不起作用。我怀疑这与单独的工作线程有关。我还没有找到任何关于以这种方式捕获异常的工作。
我想我可以创建一个 Task 对象,然后 运行 但我更愿意保留此架构,因为其中包含的代码非常复杂。
public void MethodOne(){
try{
MethodTwo(response =>{
//Do something with the response
});
}
catch(Exception error){
//This never executes when method two throws exception
}
}
public void MethodTwo(Action<Object> callback){
//Conduct async call to external server
AppServer.MakeCall( response =>{
if(response.IsValid)
callback(response.Object);
else
throw new FooException();
});
}
因为这个程序是异步的,回调甚至在 MethodTwo
返回很久之后才被调用并且该线程继续离开 try
块并做更大更好的事情.在可能遥远的未来的某个时刻,另一个线程正在调用回调。
正如您自己提到的,一种可能性是使用 Task
而不是使用回调。 TPL 的主要优点之一是它处理错误的方式。如果异步方法 returns a Task
,您不仅可以使用 ContinueWith
(或 await
)添加回调,还可以处理这些延续中的错误。
使用回调处理此问题的方法是接受两个回调,一个在响应有效时调用,另一个在有 exception/error 时调用。对于调用者来说,它不像使用 try/catch
那样漂亮,但它是您在基于回调的模型中可以做的最好的事情。
Servy说得对。因为它已经是异步的,所以可能不需要使用另一个线程或任务。但是您可以为此使用 TaskCompletionSource 。
public void MethodOne()
{
MethodTwo()
.ContinueWith(task =>
{
if (task.IsFaulted)
// Handle error in task.Exception
;
else
{
object obj = task.Result;
// Handle object
}
});
}
public Task<object> MethodTwo()
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
//Conduct async call to external server
AppServer.MakeCall(response =>
{
if (Response.IsValid)
tcs.TrySetResult(response.Object);
else
tcs.TrySetException(new FooException());
});
return tcs.Task;
}
您还可以在 MethodTwo lambda 参数中执行 try/catch and/or 使用完整的 Response 对象而不是仅响应数据对象实例。`
public void MethodOne()
{
MethodTwo(response =>
{
if (Response.IsValid)
callback(Response.Object);
else
throw new FooException(); // Or error handling directly
});
}
public void MethodTwo(Action<Response> callback)
{
//Conduct async call to external server
AppServer.MakeCall(response =>
{
callback(response);
});
}
如果不允许从 MethodOne 引用 Response 对象,and/or 不允许更改回调签名,那么您可以使用 FooException 作为参数调用回调操作 callback(new FooException);
public void MethodOne()
{
MethodTwo(response =>
{
if (response is FooException)
{
FooException exc = response as FooException;
}
else
{
// Handle response;
}
});
}
public void MethodTwo(Action<object> callback)
{
//Conduct async call to external server
AppServer.MakeCall(response =>
{
if (Response.IsValid)
callback(Response.Object);
else
callback(new FooException());
});
}