The methods that return Task
have two options for reporting an error:
- throwing exception right away
- returning the task that will finish with exception
Should the caller expect both types of error reporting or is there some standard/agreement that limits task behavior to the second option?
Example:
class PageChecker {
Task CheckWebPage(string url) {
if(url == null) // Argument check
throw Exception("Bad URL");
if(!HostPinger.IsHostOnline(url)) // Some other synchronous check
throw Exception("Host is down");
return Task.Factory.StartNew(()=> {
// Asynchronous check
if(PageDownloader.GetPageContent(url).Contains("error"))
throw Exception("Error on the page");
});
}
}
Handling both types looks pretty ugly:
try {
var task = pageChecker.CheckWebPage(url);
task.ContinueWith(t =>
{
if(t.Exception!=null)
ReportBadPage(url);
});
}
catch(Exception ex) {
ReportBadPage(url);
}
Using async/await may help, but is there a solution for plain .NET 4 without asynchronous support?
Most
Task
-returning methods are intended for use withasync
/await
(and as such should not useTask.Run
orTask.Factory.StartNew
internally).Note that with the common way of calling asynchronous methods, it doesn't matter how the exception is thrown:
The difference only comes in when the method is called and then awaited later:
However, usually the call (
CheckWebPagesAsync()
) and theawait
are in the same block of code, so they would be in the sametry
/catch
block anyway, and in that case it also (usually) doesn't matter.There is no standard. Preconditions are a type of boneheaded exception, so it doesn't really matter how it's thrown because it should never be caught anyway.
Jon Skeet is of the opinion that preconditions should be thrown directly ("outside" the returned task):
This provides a nice parallel to LINQ operators, which are guaranteed to throw exceptions "early" like this (outside the enumerator).
But I don't think that's necessary. I find the code is simpler when throwing preconditions within the task:
Remember, there should never be any code that catches preconditions, so in the real world, it shouldn't make any difference how the exception is thrown.
On the other hand, this is one point where I actually disagree with Jon Skeet. So your mileage may vary... a lot. :)