在.NET中,返回类型为 Task<T>
的方法并不一定要标记为 async
。这是因为 async
关键字只是用来告诉编译器该方法中包含异步操作,并且可以使用 await
和其他异步特性(如 Task.WhenAll
)来等待异步操作完成。
如果一个方法中没有使用 await
或者其他异步特性,但是返回类型为 Task<T>
,那么该方法仍然是异步方法。它返回的任务(Task<T>
)表示一项异步操作,可以被等待。
例如,以下示例中的 DoSomethingAsync
方法返回一个 Task<int>
对象,但是没有使用 async
关键字:
public Task<int> DoSomethingAsync()
{
return Task.Run(() =>
{
// 在此方法中执行一些异步操作,例如读写文件、调用Web服务等。
// 这里使用 Task.Run 来模拟一些耗时的操作。
Thread.Sleep(TimeSpan.FromSeconds(1)); // 睡眠1秒钟
return 42; // 返回异步操作的结果
});
}
在上述示例中,DoSomethingAsync
方法使用 Task.Run
来开启一个新的线程执行异步操作,然后返回结果。虽然该方法没有标记为 async
,但是它返回的 Task<int>
对象同样可以使用 await
关键字等待异步操作完成。例如:
int result = await DoSomethingAsync();
在调用 DoSomethingAsync
方法时,返回的 Task<int>
对象表示一项异步操作,可以使用 await
关键字等待操作完成。因此,即便方法没有标记为 async
,它仍然属于异步方法。
坑点
public Task<int> DoSomethingAsync()
{
return default;
}
由于返回Task<int>的异步方法代码,可以通过客户代码await等待异步方法结果,可以直接拿到T的结果。而如果异步方法里直接return default相当于是返回了null而不是一个Task<int> 也就无法等待了。await null就会报错。IDE对于此类问题并没有给出友好的警告或者提示。
解决方案
将方法返回类型从 Task<int?>
改为 Task<Result<int>>
,其中 Result<T>
是自定义的一个类,用于表示异步操作的执行结果。具体实现如下:
public Task<int> DoAsync()
{
return default;
}
public async Task<Result<int>> DoSomethingAsync()
{
string msg = string.Empty;
if (string.IsNullOrWhiteSpace(msg))
{
return Result<int>.Fail("错误提示.");
}
var count = await DoAsync();
return Result<int>.Success(count ?? 0);
}
调用该方法时,需要检查 Result
对象的 IsSuccess 属性,以判断该异步操作是否成功。如果成功,则可以使用 Value 属性获取查询结果。否则,可以使用 Message 属性获取错误信息。