ChatGPT解决这个技术问题 Extra ChatGPT

您如何实现异步操作委托方法?

一点背景资料。

我正在学习 Web API 堆栈,我正在尝试以“Result”对象的形式封装所有数据,其中包含 SuccessErrorCodes 等参数。

然而,不同的方法会产生不同的结果和错误代码,但结果对象通常会以相同的方式实例化。

为了节省一些时间并进一步了解 C# 中的 async/await 功能,我尝试将我的 Web API 操作的所有方法主体包装在一个异步操作委托中,但遇到了一些障碍。 ..

给定以下类:

public class Result
{
    public bool Success { get; set; }
    public List<int> ErrorCodes{ get; set; }
}

public async Task<Result> GetResultAsync()
{
    return await DoSomethingAsync<Result>(result =>
    {
        // Do something here
        result.Success = true;
        
        if (SomethingIsTrue)
        {
            result.ErrorCodes.Add(404);
            result.Success = false;
        }
    }
}

我想编写一个对 Result 对象执行操作并返回它的方法。通常通过同步方法

public T DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()
{
    T result = new T();
    resultBody(result);
    return result;
}

但是如何使用 async/await 将此方法转换为异步方法?

这是我尝试过的:

public async Task<T> DoSomethingAsync<T>(Action<T, Task> resultBody) 
    where T: Result, new()
{
    // But I don't know what do do from here.
    // What do I await?
}
如果您正在 new-ing T,为什么您的方法需要是异步的? AFAIK 在代码中使用 异步 API,您只需从您使用的其他方法传播 asyncness。
对不起,我对此还是很陌生,当你说你只需要传播时,你是什么意思,新的 T 与它有什么关系?
我想我想通了,谢谢millimoose,你给了我一些思考。
您为什么还要尝试异步执行此操作?更常见的是,在网络服务器情况下,通过将同步代码包装在任务中(就像你试图做的那样)来做假异步比仅仅同步做要慢。
@AlbinAnke“传播”我的意思是 if 您在方法中调用像 Stream.ReadAsync() 这样的 .NET 方法,该方法本身应该是异步的,并返回一个 Task<T> 其中 T是您返回的方法是同步的。想法是这样,您方法的每个调用者都可以“异步等待”(我不知道这个术语是什么好词)以完成底层 Stream.ReadAsync()。您可以使用的一个比喻是异步是“传染性的”,并且从低级内置 I/O 传播到其他代码,其结果取决于所述 I/O 的结果。

S
Stephen Cleary

Action<T>async 等效项是 Func<T, Task>,所以我相信这就是您要寻找的:

public async Task<T> DoSomethingAsync<T>(Func<T, Task> resultBody)
    where T : Result, new()
{
  T result = new T();
  await resultBody(result);
  return result;
}

@Stephen显然我正在尝试在MVVM ligth Messenger中实现一些类似的东西,我可以用同样的方式实现吗?
这真太了不起了!我认为不可能进行异步操作,并且已经将其视为语言缺陷。我没有考虑过使用 Func。谢谢。
@DFSFOT:void 方法的异步等效项是返回 Task 的方法;因此,Action 的异步等效项是 Func<Task>Action<T> 的异步等效项是 Func<T, Task>。更多信息here
@DFSFOT:当异步方法没有返回值时,它应该返回 Task。如果它使用 async 关键字,那么实际的 Task 实例将由状态机创建,而不是直接由函数创建。
@JohnB:不; Func<T, Task> 是一个异步方法,它采用 T 类型的参数并且没有返回值。 Func<Task<T>> 是一种异步方法,它不接受任何参数并返回 T 类型的值。
A
Albin Anke

所以我相信实现这一点的方法是:

public Task<T> DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()
{
    return Task<T>.Factory.StartNew(() =>
    {
        T result = new T();
        resultBody(result);
        return result;
    });
}

您应该避免在 ASP.NET 上使用 Task.Run(甚至更不用说 StartNew)。
有什么更好的方法来做到这一点?
我发布了一个答案,并赞成@svick 的答案。他们都是很好的答案。