一点背景资料。
我正在学习 Web API 堆栈,我正在尝试以“Result
”对象的形式封装所有数据,其中包含 Success
和 ErrorCodes
等参数。
然而,不同的方法会产生不同的结果和错误代码,但结果对象通常会以相同的方式实例化。
为了节省一些时间并进一步了解 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,您只需从您使用的其他方法传播 async
ness。
Stream.ReadAsync()
这样的 .NET 方法,该方法本身应该是异步的,并返回一个 Task<T>
其中 T
是您返回的方法是同步的。想法是这样,您方法的每个调用者都可以“异步等待”(我不知道这个术语是什么好词)以完成底层 Stream.ReadAsync()
。您可以使用的一个比喻是异步是“传染性的”,并且从低级内置 I/O 传播到其他代码,其结果取决于所述 I/O 的结果。
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;
}
所以我相信实现这一点的方法是:
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;
});
}
Task.Run
(甚至更不用说 StartNew
)。
void
方法的异步等效项是返回Task
的方法;因此,Action
的异步等效项是Func<Task>
,Action<T>
的异步等效项是Func<T, Task>
。更多信息here。Task
。如果它使用async
关键字,那么实际的Task
实例将由状态机创建,而不是直接由函数创建。Func<T, Task>
是一个异步方法,它采用T
类型的参数并且没有返回值。Func<Task<T>>
是一种异步方法,它不接受任何参数并返回T
类型的值。