Mike
Mike

Reputation: 5499

Is it possible to determine if a method returns a Task and await it if it does?

My goal is to pass any function with a return type to my Execute method and serialize and store its results. Below is a rough idea of what I am trying to do, obviously won't compile but hopefully it gets the idea across. I suppose I should also be able to handle nested Tasks recursively. Thoughts?

public static TResult Execute<TResult>(Func<TResult> method)
        where TResult : class
    {

        var result = method();
        if(result is Task)
        {
            var taskResult = await result;
            StoreResult(taskResult);
        }
        else
        {
            StoreResult(result);
        }
    }

Upvotes: 2

Views: 262

Answers (2)

svick
svick

Reputation: 244757

I agree with Lee's comment that having a separate overload for Func<Task<TResult>> is the right solution.

But if you really want to do this using one overload, you could use reflection and dynamic to make this work:

public async static Task Execute<TResult>(Func<TResult> method) where TResult : class
{
    var result = method();

    if (typeof(TResult).IsGenericType
        && typeof(TResult).GetGenericTypeDefinition() == typeof(Task<>))
    {
        var taskResult = await (dynamic)result;
        StoreResult(taskResult);
    }
    else
    {
        StoreResult(result);
    }
}

Upvotes: 1

Tim M.
Tim M.

Reputation: 54359

Here's a contrived example that shows how it can be done.

I'd question the wisdom of this pattern. I'd prefer to always return a task, even if a task isn't always needed. The overhead of Task.FromResult() is usually negligible.

public async Task<T> Foo<T>()
{
    var mightBeATask = Bar<T>();
    var task = mightBeATask as Task<T>;

    if( task != null )
    {
        return await task;
    }

    return (T)mightBeATask;
}

private object Bar<T>()
{
    return Task.FromResult( default( T ) );
}

Upvotes: 2

Related Questions