【问题标题】:How to create a new generic Task using an async lamda as argument如何使用异步 lambda 作为参数创建新的通用任务
【发布时间】:2021-09-20 11:55:57
【问题描述】:

我需要创建一个新的通用任务,它采用异步 lambda,但不会立即启动。这就是为什么我不能使用Task.Run 并且我想实例化一个新任务。我不能这样做,因为 C# 给了我以下错误:

无法将异步 lambda 表达式转换为委托类型 Func<int>。 异步 lambda 表达式可能返回 voidTaskTask<T>,没有一个 可转换为Func<int>

我的代码是

Task<int> task = new Task(async () => {
    var number = await getNextNumber();
    return await algorithm(number);
});

【问题讨论】:

  • 需要返回值吗?像这样的异步函数,好像不能有返回值。
  • @Nigel 我是否正确理解您需要延迟执行的异步函数?
  • 问题解决了吗?你看过斯蒂芬克利里的回答吗?

标签: c# task


【解决方案1】:

我需要创建一个新的通用任务,它采用异步 lambda,但不会立即启动。这就是为什么我不能使用 Task.Run 并且我想实例化一个新任务的原因。

你应该never, ever use the Task constructor,正如我在我的博客中解释的那样。

在同步世界中,如果您想要一个可以稍后调用的对象来执行某些代码,您可以使用委托,例如 ActionFunc&lt;T&gt;

在异步世界中,如果您想要一个可以稍后调用的对象来执行某些代码,您可以使用委托。 The delegate types for asynchronous lambdas are different than the synchronous ones,正如我在博客中解释的那样;所以你可以用Func&lt;Task&gt;代替Action,用Func&lt;Task&lt;T&gt;&gt;代替Func&lt;T&gt;

Func<Task<int>> func = async () => {
    var number = await getNextNumber();
    return await algorithm(number);
};

...

int result = await func();

【讨论】:

  • 我读了你的博客,你的解释很精彩,你值得称赞。
【解决方案2】:

通用任务类 Task&lt;T&gt; 没有将 Func&lt;Task&lt;T&gt;&gt; 作为参数的构造函数,因此您不能使用 async 关键字装饰您的 lambda。但是,非泛型任务类 Task 确实允许传入异步 lamdas。

一种解决方法是围绕Task&lt;T&gt; 类创建一个包装器,以使您也可以等待内部任务的方式实现这一点。

public class SuperTask<T>
{
    private Task<T> task;
    private Func<Task<T>> function;
    public SuperTask(Func<Task<T>> function)
    {
        this.function = function;
    }
    public SuperTask<T> Start()
    {
        task = function();
        return this;
    }
    public Task<T> AsTask() {
        return task;
    }
}

// And you can test it like so
SuperTask<int> testCase = new SuperTask<int>(async ()=> {
   await Task.Delay(1000); 
   return 0;
});
int number = await testCase.Start().AsTask();

【讨论】:

    【解决方案3】:

    这个方法怎么样:

    Task<int> task = new Task<int>(() =>
        getNextNumber()
            .ContinueWith(t => algorithm(t.Result))
            .Unwrap()
            .Result
    );
    

    好旧的ContinueWith 加上Unwrap

    它看起来很难看,但它应该可以工作。

    【讨论】:

    猜你喜欢
    • 2019-10-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-01
    • 1970-01-01
    • 2019-02-07
    • 2020-05-07
    • 1970-01-01
    • 2023-02-15
    相关资源
    最近更新 更多