使用 .NET 任务并行库捕获错误
Catching errors with .NET Task Parallel Library
这是我尝试过的两种用于捕获错误的备选方案,它们似乎都在做同样的事情..但是一个比另一个更可取,为什么?
备选方案 1:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
Task t = Task.Run(() =>
{
_someObj.SomeMethod();
});
await t; //wait here, without blocking...
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
return; //<-- bypass below code on error...
}
//other code below... does not execute...
DoSomethingElse();
}
备选方案 2:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool errOccurred = false;
Task t = Task.Run(() =>
{
try
{
_someObj.SomeMethod();
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
errOccurred = true;
}//end-Catch
});
await t; //wait here, without blocking...
if (errOccurred) return; //<-- bypass below code on error...
//other code below... does not execute...
DoSomethingElse();
}
更好的选择是将部分代码重构为一个单独的方法,该方法返回一个指示是否继续的布尔值。
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool success = await SomeMethodAsync();
if (!success)
{
return;
}
//other code below... does not execute...
DoSomethingElse();
}
private async Task<bool> SomeMethodAsync()
{
try
{
await Task.Run(() => _someObj.SomeMethod());
return true;
}
catch (Exception ex)
{
string errMsg = string.Format("{0} {1}some unhandled error occurred in SomeMethod",
ex.Message, Environment.NewLine);
Log(errMsg);
return false;
}
}
重构代码比将所有代码放在一起更好place.It如果您需要做的只是记录异常,那么最好在委托中捕获异常。
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
}
但是,如果您有另一种方法 DoSomethingElse()
,它可能会受到 Task.It 的结果的影响,最好将 try catch
包裹在 await
[=15= 周围]
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
DoSomethingElse();
}
catch(Exception ex)
{
}
}
与它所依赖的任何事物一样。
我想说将 Task.Run() 部分重构为一个单独的异步任务方法,就像 Sriram Sakthivel 的回答一样,通常是一件好事。它避免了在版本 2 中在 lambda 中使用捕获的布尔值,并且它允许您编写更简洁地表达意图的代码。
也就是说,我会仔细考虑 "catch all -> log -> ignore" 模式是否是您想要的。总的来说:捕获特定的异常并专门处理它们。对于所有其他异常,您可以记录它们,但仍然使用 "throw;" 或 "throw new MoreSpecificException(originalException);".
重新抛出它们
考虑到这一点,我建议如果您采用全捕获方法,您应该像版本 1 中那样进行全捕获。
为了保持高可读性,使代码简洁明了,并明确处理异常,我会这样写:
private async void BtnClick(object sender, RoutedEventArgs e)
{
try
{
if (await TryDoSomethingAsync())
{
DoSomeMoreStuff();
}
}
catch (Exception ex)
{
// I am sure it is fine that any and all exceptions can be logged and ignored.
Log(ex);
// And maybe even notify the user, since I mean, who monitors log files anyway?
// If something that shouldn't go wrong goes wrong, it's nice to know about it.
BlowUpInYourFace(ex);
}
}
private async Task<bool> TryDoSomethingAsync()
{
return await Task.Run<bool>(() =>
{
try
{
_myService.DoSomething();
}
catch (SomeKnownException ske)
{
// An expected exception which is fine to ignore and return unsuccessful.
Log(ske);
return false;
}
catch (SomeOtherKnownException soke)
{
// Expected exception that indicates something less trivial, but could be more precise.
throw new MyMorePreciseException(soke);
}
// Nothing went wrong, so ok.
return true;
});
}
这是我尝试过的两种用于捕获错误的备选方案,它们似乎都在做同样的事情..但是一个比另一个更可取,为什么?
备选方案 1:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
Task t = Task.Run(() =>
{
_someObj.SomeMethod();
});
await t; //wait here, without blocking...
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
return; //<-- bypass below code on error...
}
//other code below... does not execute...
DoSomethingElse();
}
备选方案 2:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool errOccurred = false;
Task t = Task.Run(() =>
{
try
{
_someObj.SomeMethod();
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
errOccurred = true;
}//end-Catch
});
await t; //wait here, without blocking...
if (errOccurred) return; //<-- bypass below code on error...
//other code below... does not execute...
DoSomethingElse();
}
更好的选择是将部分代码重构为一个单独的方法,该方法返回一个指示是否继续的布尔值。
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool success = await SomeMethodAsync();
if (!success)
{
return;
}
//other code below... does not execute...
DoSomethingElse();
}
private async Task<bool> SomeMethodAsync()
{
try
{
await Task.Run(() => _someObj.SomeMethod());
return true;
}
catch (Exception ex)
{
string errMsg = string.Format("{0} {1}some unhandled error occurred in SomeMethod",
ex.Message, Environment.NewLine);
Log(errMsg);
return false;
}
}
重构代码比将所有代码放在一起更好place.It如果您需要做的只是记录异常,那么最好在委托中捕获异常。
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
}
但是,如果您有另一种方法 DoSomethingElse()
,它可能会受到 Task.It 的结果的影响,最好将 try catch
包裹在 await
[=15= 周围]
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
DoSomethingElse();
}
catch(Exception ex)
{
}
}
与它所依赖的任何事物一样。
我想说将 Task.Run() 部分重构为一个单独的异步任务方法,就像 Sriram Sakthivel 的回答一样,通常是一件好事。它避免了在版本 2 中在 lambda 中使用捕获的布尔值,并且它允许您编写更简洁地表达意图的代码。
也就是说,我会仔细考虑 "catch all -> log -> ignore" 模式是否是您想要的。总的来说:捕获特定的异常并专门处理它们。对于所有其他异常,您可以记录它们,但仍然使用 "throw;" 或 "throw new MoreSpecificException(originalException);".
重新抛出它们考虑到这一点,我建议如果您采用全捕获方法,您应该像版本 1 中那样进行全捕获。
为了保持高可读性,使代码简洁明了,并明确处理异常,我会这样写:
private async void BtnClick(object sender, RoutedEventArgs e)
{
try
{
if (await TryDoSomethingAsync())
{
DoSomeMoreStuff();
}
}
catch (Exception ex)
{
// I am sure it is fine that any and all exceptions can be logged and ignored.
Log(ex);
// And maybe even notify the user, since I mean, who monitors log files anyway?
// If something that shouldn't go wrong goes wrong, it's nice to know about it.
BlowUpInYourFace(ex);
}
}
private async Task<bool> TryDoSomethingAsync()
{
return await Task.Run<bool>(() =>
{
try
{
_myService.DoSomething();
}
catch (SomeKnownException ske)
{
// An expected exception which is fine to ignore and return unsuccessful.
Log(ske);
return false;
}
catch (SomeOtherKnownException soke)
{
// Expected exception that indicates something less trivial, but could be more precise.
throw new MyMorePreciseException(soke);
}
// Nothing went wrong, so ok.
return true;
});
}