Как связать задачу с другой задачей, не зная тип результата первой задачи - PullRequest
0 голосов
/ 16 августа 2011

Предположим, у меня есть API, который возвращает задачу в виде объекта:

    private static object CreateTask()
    {
        return Task.Factory.StartNew(() => "Task string");
    }

Мне нужно расширить API с помощью функции, которая возвращает другую задачу, связанную с задачей, возвращенной функцией CreateTask, чтобы новыйРезультат задачи будет результатом начальной задачи.Т.е. что-то вроде этого:

    private static object WrapTask(dynamic task)
    {
        object new_task = task.ContinueWith(parentTask => parentTask.Result, TaskContinuationOptions.ExecuteSynchronously);

        return new_task;
    }

Пример использования:

        var task = (Task<string>)WrapTask(CreateTask());

        Console.WriteLine(task.Result);

должен печатать строку "Task string".

Проблема с функцией WrapTask заключается в том, чточто компилятор отказывается принять эту конструкцию:

        object result = task.ContinueWith(parentTask => parentTask.Result, TaskContinuationOptions.ExecuteSynchronously);

со следующей ошибкой:

        Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type

Буду признателен за любые идеи о расширении API описанным способом.

1 Ответ

2 голосов
/ 16 августа 2011

Вы можете использовать динамическую типизацию для вызова универсального метода с выводом типа, обеспечиваемым динамической типизацией:

private static object WrapTask(dynamic task)
{
    return WrapTaskImpl(task);
}

private static Task<T> WrapTaskImpl<T>(Task<T> task)
{
    return task.ContinueWith(parentTask => parentTask.Result,
        TaskContinuationOptions.ExecuteSynchronously);
}

Не совсем понятно, в чем смысл этой упаковки, обратите внимание ... нипочему вы хотите просто разыграть результат из WrapTask - если вы знаете, что это Задача, почему бы вам не разыграть результат CreateTask вместо этого, в этот момент вы можете вызвать WrapTask просто?Или, может быть, WrapTask сам выполняет кастинг?

private static Task<T> WrapTask<T>(object task)
{
    Task<T> realTask = (Task<T>) task;
    return realTask.ContinueWith(parentTask => parentTask.Result, 
                                 TaskContinuationOptions.ExecuteSynchronously);
}

Тогда ваш код вызова становится

var task = WrapTask<string>(CreateTask());

Console.WriteLine(task.Result);
...