开发者

How do I chain a task to another task without knowing the first task's result type

开发者 https://www.devze.com 2023-03-28 18:16 出处:网络
Suppose I have an API that returns a Task as an object: private static object CreateTask() { return Task.Factory.StartNew(() => \"Task string\");

Suppose I have an API that returns a Task as an object:

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

I need to extend the API with a function that returns another Task chained to the Task returned by CreateTask function so that the new Task's result would be the result of the initial Task. I.e. something like this:

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

        return new_task;
    }

The usage sample:

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

        Console.WriteLine(task.Result);

is supposed to print "Task string" string.

The problem with the WrapTask function is that the compiler refuses to accept this construction:

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

with the following error:

        Cannot开发者_运维问答 use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type

Would appreciate any ideas on how to go about extending the API in the described way.


You could use dynamic typing to call a generic method with type inference provided by the dynamic typing:

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);
}

It's not at all clear what the point of this wrapping is, mind you... nor why you'd want to just cast the result of WrapTask - if you know that it's a Task, why don't you cast the result of CreateTask instead, at which point you can call WrapTask simply? Or maybe make WrapTask perform the casting itself?

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

Then your calling code becomes

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

Console.WriteLine(task.Result);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号