There are a lot of common bool TryXXX(out T result) methods in the .NET BCL, the most popular being, probably, int.TryParse(...).
I would like to implement an async TryXXX() method. Obviously, I can't use out parameters.
Is there an established pattern for this?
More to the point, I need to download and parse a file. It's possible that the file does not exist.
This is what I came up with so far:
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; }
}
I've come up with the following definitions. The defaultValue parameters are there mostly to be able to overload the TryGet method, as generic constraints are not part of a method's signature, that which makes the method unique when deciding which method to call (for instance, the return type is also not part of the signature).
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;
}
}
You should review exception handling, this example handles the common parsing exceptions. It may make more sense to react to other exceptions, such as InvalidOperationException and NotSupportedException, probably the most used exception types on the framework itself (not necessarily the most commonly thrown ones).
Another approach is to re-throw critical exceptions, such as ThreadAbortException and have a simple catch-all clause that returns the default value. However, this will hide every exception not deemed critical, no matter how severe it is.
As such, and because throwing exceptions is an expensive operation, it's Parse that is usually defined in terms of TryParse. So your TryGet should have a contract, e.g. deal with OperationCanceledException, which includes TaskCanceledException and nothing else.
Finally, you should name it TryGetAsync, following the Async-suffix convention. [1] [2]
One of possible decisions is an array of ParsedFile, containing 0 or 1 element.
public async Task<ParsedFile[]> TryDownloadAndParse(string fileUri)
{
try
{
return new[] { await DownloadAndParse(fileUri) };
}
catch (DownloadNotFoundException ex)
{
return new ParsedFile[0];
}
}
Now you can check the result:
. . .
var parsedFiles = await TryDownloadAndParse(url);
if (parsedFiles.Any())
{
var parsedFile = parsedFiles.Single();
// more processing
}
. . .
If you want to call void method, you can use ?. operator:
var parsedFiles = await TryDownloadAndParse(url);
parsedFiles.SingleOrDefault()?.DoVeryImportantWorkWithoutResult();
UPDATE
In Azure you can use ConditionalValue<TValue> class.
Related
To describe the result of any business operation,
I have the following Result class
public class Result<TResponse>
{
public TResponse? Response { get; set; }
public Exception? Exception { get; set; }
internal Result(TResponse response, Exception exception)
{
Response = response;
Exception = exception;
}
public static implicit operator Result<TResponse>(TResponse response)
{
return new Result<TResponse>(response, default);
}
public static implicit operator Result<TResponse>(Exception e)
{
return new Result<TResponse>(default, e);
}
//TODO other codes that I want to ask
}
It overloaded operators for TResponse and Exception
So I can use the following code happily:
public Result<int> Method1()
{
try
{
//do_some_sync_stuff()
return 42;//will return Result<int>(42,null)
}
catch (Exception e)
{
return e;//will return Result<int>(null,e)
}
}
Now I want to use async version of the latest code like that:
public async Result<int> Method2()
{
try
{
//await do_some_async_stuff()
return 42;//example value
}
catch (Exception e)
{
return e;
}
}
But dotnet gets angry and says:
error CS1983: The return type of an async method must be void, Task, Task<T>, a task-like type, IAsyncEnumerable<T>, or IAsyncEnumerator<T>
Is there a way to achive that ?
I know I can use Task<Result<int>> but it is way more complicated to use like that- nested generics
I have tried to add GetAwaiter and implement AsyncMethodBuilder but can't success -returning exceptions do not work
Related links but not solving exactly that issue:
link1 link2 link3
If you want to do a async processing in your method you need to have a return type like Task. Because the compiler its doing a cast like
Result<int> = Task<Result<int>>
because of the async method.
If you add the Task return type, the cast should work fine.
I should have a function that must return either a string of an error (through try / catch) or a different type T.
Example of such a function:
public T get()
{
T struttura;
try {
...
}
catch (Exception xcp) {
return xcp.Message;
}
...
return struttura;
}
There are ways to do this, but really consider if that's what you actually want. It is almost always better just to let the Exception bubble upwards into the calling code.
The first way is to use an out parameter.
public string get(out T result)
{
T struttura;
try{...}
catch (Exception xcp)
{
result = default(T);
return xcp.Message;
}
...
result = struttura;
return String.Empty;
}
The second way is to use a ValueTuple:
public (T, string) get()
{
T struttura;
try{...}
catch (Exception xcp){return (default(T), dexcp.Message);}
...
return (struttura, string.Empty);
}
The .net design guidelines https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/exception-throwing recommend never returning the exception as a return type. It’s always better design to throw the error and catch in the caller.
The guidelines also recommend that if you don’t want to throw the error that you can follow the TryParse pattern https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/exceptions-and-performance#try-parse-pattern. Typically you provide both methods, Get and TryGet. The presence of the Try method should indicate to callers that Get will throw exceptions but TryGet won’t. The TryGet also returns a Boolean if the operation was successful, allowing you to handle negative cases without using a try/catch block on the caller.
I suggest TryGet signature:
public bool TryGet(out T struttura) {
try {
...
struttura = ...
...
return true;
}
catch (Exception xcp){
struttura = default(T);
return false;
}
}
Usage:
if (TryGet(out var myStruct)) {
// succeeded, myStruct is returned struttura
}
else {
// failed
}
Or either do not catch exceptions at all or re-throw exception as custom one:
public T Get() {
try {
...
return struttura;
}
catch (Exception xcp) {
throw new MyException("My message", xcp);
}
}
Usage:
try {
myStruct = Get();
}
catch (MyException e) {
// Failed, e.Message for message
Console.WriteLine(e.Message);
}
Finally, you can mechanically combine value and message and return named tuple:
public (T value, string message) Get() {
try {
...
return (struttura, null);
}
catch (Exception xcp) {
return (default(T), xcp.message);
}
}
Usage:
var result = Get();
if (result.message == null) {
// succceded with result.value
}
else {
// failed with result.message
}
I have many statements that can throw exceptions. Exceptions are not important.
My system accepts missing patient data fields.
patientData.PatientId = message.Find(...);
try
{
patientData.Gender = message.Find(...);
}
catch
{
// no gender, no problem
}
try
{
patientData.DateOfBirth = message.Find(...);
}
catch
{
// no DateOfBirth, no problem
}
// and many other try-catch blocks ...
What is the best way to write these statements that can throw exceptions but not critical?
In your example, you can create static TryFindMessage method in addition to Find. In case of exception just return false.
For example:
bool Message.TryFind(..., Message message, out string result).
But, if you wish some generic approach which you can use with anything, then you can take advantage of delegates and create some static helper.
You can use Action or Func in that case. Add another extension method which accepts Func if you need to return some value from executed function.
public static class SilentRunner
{
public static void Run(Action action, Action<Exception> onErrorHandler)
{
try
{
action();
}
catch (Exception e)
{
onErrorHandler(e);
}
}
public static T Run<T>(Func<T> func, Action<Exception> onErrorHandler)
{
try
{
return func();
}
catch (Exception e)
{
onErrorHandler(e);
}
return default(T);
}
}
And then use it so:
SilentRunner.Run(
() => DoSomething(someObject),
ex => DoSomethingElse(someObject, ex));
In case of Func, you can take result as well:
var result = SilentRunner.Run(
() => DoSomething(someObject),
ex => DoSomethingElse(someObject, ex));
I have many statements that can throw exceptions. Exceptions are not
important.
This can be dangerous, because exceptions can be thrown for different reasons, not only because of missing property.
I would advise instead of swallowing exception, modify code to return default value(null) when value is not found.
You can introduce new method in message class, for example FindOrDefault
// Pseudo code
public T FindOrDefault(string property)
{
return CanFind(property) ? Find(property) : default(T);
}
Usage of such method will be self explanatory
patientData.PatientId = message.Find(...); // Mandatory - must throw if not found
patientData.Gender = message.FindOrDefault(...);
patientData.DateOfBirth = message.FindOrDefault(...);
I have this method:
public object LongRunningTask()
{
return SomethingThatTakesTooLong();
}
I wrote the following code so I can transform a normal method in an async one and still get the Exception:
public async Task<object> LongRunningTaskAsync()
{
Exception ex = null;
object ret = await Task.Run(() =>
{
object r = null;
try
{
//The actual body of the method
r = SomethingThatTakesTooLong();
}
catch (Exception e)
{
ex = e;
}
return r;
});
if (ex == null)
return ret;
else
throw ex;
}
When I need to do this in several methods, I have to copy all this code and change only the middle.
Is there a way to do something like this?
[SomeAttributeThatDoesThatMagically]
public async Task<object> LongRunningTaskAsync()
{
return SomethingThatTakesTooLong();
}
Attributes are generally metadata though it is possible to define attributes that can be executed (such as security behaviours in WCF) however, something has to be looking for it first. Your attributes won't just magically run.
I suspect you might have to use a dynamic proxy.
Take a look at how WCF does things for ideas.
I implemented a Global Try Catch mechanism in this way. I added a seperate class called HandleException.cs
public static class HandleException
{
public static void GlobalTryCatch(Action action, object obj)
{
try
{
action.Invoke();
}
catch(SqlException ex)
{
obj.GetType().GetProperty("Success").SetValue(obj.GetType(), false);
obj.GetType().GetProperty("FailureMessage").SetValue(obj.GetType(), ex);
}
catch(Exception ex)
{
obj.GetType().GetProperty("Success").SetValue(obj.GetType(), false);
obj.GetType().GetProperty("FailureMessage").SetValue(obj.GetType(), ex);
}
}
}
And this way calling it.
public override Result<int> Update(UserProfile data)
{
var result = new Result<int> { Success = false };
HandleException.GlobalTryCatch(() =>
{
SqlParameter[] sParam =
{
DbHelper.CreateParameter("#UserId", ParameterDirection.Input, SqlDbType.Int, data.UserId),
DbHelper.CreateParameter("#FirstName", ParameterDirection.Input, SqlDbType.VarChar,100, data.FirstName),
DbHelper.CreateParameter("#LastName", ParameterDirection.Input, SqlDbType.VarChar,100, data.LastName),
DbHelper.CreateParameter("#Gender", ParameterDirection.Input, SqlDbType.Char,1, data.Gender),
DbHelper.CreateParameter("#Dob", ParameterDirection.Input, SqlDbType.Date, data.DateOfBirth),
DbHelper.CreateParameter("#ImageUrl", ParameterDirection.Input, SqlDbType.VarChar, 150, data.ImageUrl),
};
using(var sql = new DbHelper())
{
sql.ExecuteSpReturnScalar("UserProfile_Update", sParam);
}
result.Success = true;
}, result);
return result;
}
My questions are
Is this a standard practice for implementing global try catch mechanism or Is there any other standard way to implement this?
I had used this in GlobalTryCatch method. Whether this way we can assign value to a property by passing Generic Object?
obj.GetType().GetProperty("Success").SetValue(obj.GetType(), false);
Is this a standard practice for implementing global try catch mechanism
No, it is not. Moreover, mentioned "global try-catch mechanism" is a bad practice. Wrapping every method in try-catch assumes, that you definitely know, what to do after any exception has been thrown. In the real world this is false. Look at this sample:
void AnyMethod()
{
var result = // ...
HandleException.GlobalTryCatch(() => { /* action 1 */}, result);
// should we check result to continue?
// if so, this is a typical error-code approach, which annihilates
// all preferences, provided by .NET exceptions;
// if we shouldn't check it, what would be the behavior of our code,
// if the state is broken after action 1?
HandleException.GlobalTryCatch(() => { /* action 2 */}, result);
// the same questions
HandleException.GlobalTryCatch(() => { /* action 3 */}, result);
}
Similar approach from time-to-time being used to log exceptions (due to absence of out-of-box aspects inmplementation in .NET):
void Execute(Action action)
{
try
{
action();
}
catch (Exception e)
{
Logger.Log(e);
throw;
}
}
T Execute<T>(Func<T> func)
{
try
{
return func();
}
catch (Exception e)
{
Logger.Log(e);
throw;
}
}
but:
1) it logs full exception information (e.g., your code is missing stack trace and inner exceptions);
2) it re-throws the same exception (this allows to use all benefits from .NET exceptions);
3) it wraps only limited number of top-level methods, not every method.
Whether this way we can assign value to a property by passing Generic Object?
You could do something like this:
interface IActionResult
{
bool Success { get; set; }
string FailureMessage { get; set; }
}
public static void GlobalTryCatch<T>(Action action, T obj)
where T : IActionResult
{
// ...
}
but this doesn't cancel answer on your 1st question.
You can use http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx (or http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx for WPF applications).
Generally it is not a bad idea to do something meaningful during this events - logging the exceptions (or sending them to admin) and displaying a message to user (something like "Sorry, error occurred, contact your admin please").
But as others said - you should handle the excpetions in your methods where you can do something meaningful with them, not on global level. And even if it is not mandatory in c#, it's a good idea to add to comments that your method can throw some kind of exception on certain circumstances.