Question

I am working on a C# system and a class has one function that returns a System.Threading.Tasks.Task object and has a property System.Type ReturnType.

When ReturnType is null i know the method return a Task object. But sadly there is no way to know if the class implementing the interface will return a Task<ReturnType> or Task<object> and i need to get the result of this method. I think the easiest way to do it would be to convert the Task<T> to Task<object> so i can get the result and handle it using the Type value in ReturnType.

How can i convert a Task<T> to Task<object> without knowing the type of T ?

public interface ITaskFactory
{

    ReadOnlyCollection<ParameterInfo> ParametersInfo { get; }

    Type ReturnType { get; }

    Task CreateTask (params object[] args);

}

I need to get the result returned by the Task that i received by calling CreateTask()

See: http://dotnetfiddle.net/Bqwz0I

No correct solution

OTHER TIPS

I have tried quite a few things and the only things that has worked for me is using reflection. I also added code that detects tasks without a value and throws an exception.

using System;
using System.Threading.Tasks;
using System.Reflection;

public class Program
{
    private static async Task<object> Convert(Task task)
    {
        await task;
        var voidTaskType = typeof (Task<>).MakeGenericType(Type.GetType("System.Threading.Tasks.VoidTaskResult"));
        if (voidTaskType.IsAssignableFrom(task.GetType()))
            throw new InvalidOperationException("Task does not have a return value (" + task.GetType().ToString() + ")");
        var property = task.GetType().GetProperty("Result", BindingFlags.Public | BindingFlags.Instance);
        if (property == null)
            throw new InvalidOperationException("Task does not have a return value (" + task.GetType().ToString() + ")");
        return property.GetValue(task);
    }

    public static async Task Main()
    {
        Console.WriteLine("Start");
        Task i = CreateTask();
        Task<object> o = Convert(i);
        Console.WriteLine("value: {0}", await o);
        Console.WriteLine("value2: {0}", await Convert(Task.FromResult<int>(123)));

        //Test for tasks without return values
        try
        {
            Console.WriteLine("value3: {0}", await Convert(Task.CompletedTask));
        }
        catch (Exception ex)
        {
            Console.WriteLine("value3: EX {0}", ex.Message);
        }

        //Test for tasks without return values
        try
        {
            Console.WriteLine("value4: {0}", await Convert(Test4()));
        }
        catch (Exception ex)
        {
            Console.WriteLine("value4: EX {0}", ex.Message);
        }
        Console.WriteLine("Done");
    }


    private static Task CreateTask()
    {
        return Task.FromResult("Some result");
    }

    public static async Task Test4()
    {
        await Task.CompletedTask;
        return;
    }
}

Task<T> is not covariant (unlike IEnumerable<T>, see its definition, notice the out keyword) so you can only await it first then convert:

async Task<object> Do<T>(Task<T> task)
{
   // this won't compile: Cannot implicitly convert type 'Task<T>' to 'Task<object>'
   // return task;

    object result = await task;
    return result;
}

Easiest way is to use ContinueWith

    Task<T> task = null;
    Task<object> obj = task.ContinueWith(t => (object)t.Result);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top