skip to Main Content

I have following generic method in abstract class which is in many places across application:

protected T Execute<T>(Func<T> func)
 {
            try
            {
                return func();
            }
            catch (InvalidOperationException invalidEx)
            {
                throw new InvalidException(invalidEx.Message, invalidEx);
            }
            catch (SqlException sqlEx)
            {
                throw new DbException(sqlEx.Message, sqlEx, ConvertSQLError(sqlEx));
            }
 }

It is in a base class and all derived classes use this one above in order to execute delegate Func. Calling code looks something like this:

public int SomeMethodInDerivedClass(.....){
    result = Execute(() =>
    {....code ommited becouse of clarity })
  }

What would be the best way to

  1. Rewrite this method to be able to call it in an async way
  2. Use await efficiently in calling code?

What I would like to achieve, actualy to be able to rewrite SomeMethodInDerivedClass so that it can return Task instead of int? Where should I start from?

Thank you in advance

3

Answers


  1. Chosen as BEST ANSWER

    So in the end I acome up with following solution:

     protected async Task<T> ExecuteAsync<T>(Func<T> func)
        {
            try
            {
                return await Task.Run(func);
            }
    

    And calling code is like this one:

    public async Task<int> SomeMethod(......)
        {
                        
                result += await ExecuteAsync(() =>
                {
                ....code ommited for brevity 
                }
        }
    

  2. async await is like zombie curse, it will contaminate entire codebase. It’s not that bad however.
    Yes, to use efficiently async await, you need to return Task<T>. So in your example would be Task<int>.
    However is the delegate an asynchronous operation? If not you need to make it behave as one, so you need to wrap it into a Task.

    It’s quiet difficult to give you exact steps, as like I said, it should contaminate up to main, so everything operate on async await and Task, for the code to really benefit from the pattern.

    Login or Signup to reply.
  3. I think you can add another method for your async Func:

    protected async Task<T> ExecuteAsync<T>(Func<Task<T>> func)
    {
        try
        {
            return await func();
        }
        catch (InvalidOperationException)
        {
            throw;
        }
        catch (SqlException)
        {
            throw;
        }
    }
    

    If you want rethrow an exception, use previous code instead of create another exception because you lose the original exception context when you create a new one.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search