Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 如何在不知道第一个任务的情况下将一个任务链接到另一个任务';s结果类型_Generics_Reflection_Expression Trees_Task Parallel Library - Fatal编程技术网

Generics 如何在不知道第一个任务的情况下将一个任务链接到另一个任务';s结果类型

Generics 如何在不知道第一个任务的情况下将一个任务链接到另一个任务';s结果类型,generics,reflection,expression-trees,task-parallel-library,Generics,Reflection,Expression Trees,Task Parallel Library,假设我有一个将任务作为对象返回的API: private static object CreateTask() { return Task.Factory.StartNew(() => "Task string"); } 我需要使用一个函数扩展API,该函数返回另一个链接到CreateTask函数返回的任务的任务,以便新任务的结果将是初始任务的结果。也就是说,类似这样的事情: private static object WrapTask(d

假设我有一个将任务作为对象返回的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);
出现以下错误:

        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的想法,我们将不胜感激。

您可以使用动态类型调用泛型方法,并使用动态类型提供的类型推断:

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);
}
然后您的呼叫代码变为

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

Console.WriteLine(task.Result);
var task=WrapTask(CreateTask());
Console.WriteLine(task.Result);

上述API是一种简化。简而言之,实际情况是:有一个API(一组方法)返回任务。每个方法的结果可能不同。我需要设计一个解决方案,允许记录对实现该API的对象的调用。我想这是一个方面的工作。为了连接那个相位,我使用Unity的截取。因此,拦截器在API返回的原始任务上创建一个延续。在此延续中,实现了日志方面。然后,拦截器应该返回调用站点期望的任务,其中TResult是原始任务的实际结果。你为什么要问“反对”。。这是因为在拦截器中,结果可通过IMethodReturn.ReturnValue的实例获得,该实例为“object”。。或者我还缺少什么?@ay.metallo:对-这更有意义。当你呈现一个看似毫无意义的任务时,它总是在解释为什么它不是真正毫无意义的。顺便说一句,感谢你提供了优雅的解决方案(我一直都知道它一定是简单的;动力学确实很强大)!看起来还可以。@ay.metallo:那么您使用的是哪种解决方案?如果你能用后者,我会。。。
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);