在上篇文章我们简要认识了异步编程后,本章则要我们对异步的返回类型进行一定的了解和认识。
异步方法可以具有以下返回类型(常用):
Task返回类型 (对于执行操作但不返回任何值的异步方法)
Task<TResult> 返回类型 (对于返回值的异步方法)
Void 返回类型 (对于事件处理程序)
Task返回类型
Task返回类型是不包含 return 语句的异步方法或包含不返回操作数的 return 语句的异步方法。如果在异步方法中使用 Task 返回类型,调用方法可以使用 await 运算符暂停调用方的完成,直至被调用的异步方法结束。
public static async Task DisplayCurrentInfoAsync()
{
await WaitAndApologizeAsync();
Console.WriteLine($"今天日期是: {DateTime.Now:D}");
Console.WriteLine($"当前时间为: {DateTime.Now.TimeOfDay:t}");
Console.WriteLine("今天是晴天");
}
static async Task WaitAndApologizeAsync()
{
await Task.Delay(2000);
Console.WriteLine("当前网络不好,请稍后再试\n");
}
// 输出:
// 当前网络不好,请稍后再试
//
// 今天日期是 2022-6-8
// 当前时间为: 12:09:24.2183304
// 今天是晴天
Task<TResult> 返回类型
Task<TResult> 返回类型就是包含 return 语句的异步方法,其中操作数是 TResult,操作数可以简单理解成一个泛型占位符。
public static async Task ShowTodaysInfoAsync()
{
string message = $"今天是: {DateTime.Today:D}\n" + "今天学习时间: " + $"{await GetLeisureHoursAsync()} 小时";
Console.WriteLine(message);
}
static async Task<int> GetLeisureHoursAsync()
{
DayOfWeek today = await Task.FromResult(DateTime.Now.DayOfWeek);
int leisureHours = today is DayOfWeek.Saturday || today is DayOfWeek.Sunday ? 16 : 5;
return leisureHours;
}
// 输出:
// 今天是: 2022-6-8
// 今天学习时间: 5 小时
Void 返回类型
在异步事件处理程序中使用 void 返回类型,这需要 void 返回类型。 而这里的返回类型是指对于事件处理程序以外的不返回值,应返回 Task。此类方法的任何调用方都必须继续完成,而无需等待调用的异步方法完成。 调用方必须独立于异步方法生成的任何值或异常。
参考案例如下,均有注释说明:
#region 生成一个点击事件Click()
public class NaiveButton
{
public event EventHandler Clicked;
public void Click()
{
Console.WriteLine("提出请求");
Clicked?.Invoke(this, EventArgs.Empty);//Invoke调用,为下面MultipleEventHandlersAsync方法提供新增调用
Console.WriteLine("通知监听器");
}
}
#endregion
public class AsyncVoidExample
{
static readonly TaskCompletionSource<bool> s_tcs = new TaskCompletionSource<bool>();
public static async Task MultipleEventHandlersAsync() //创建一个Task异步方法
{
Task<bool> secondHandlerFinished = s_tcs.Task;
var button = new NaiveButton();//new 一个button对象
//将下列的OnButtonClicked1、OnButtonClicked2Async、OnButtonClicked3的方法逐一新增到button对象里
button.Clicked += OnButtonClicked1;
button.Clicked += OnButtonClicked2Async;
button.Clicked += OnButtonClicked3;
Console.WriteLine("Click()方法被调用前");
button.Click();//触发Click()点击事件(输出案例在底端)
Console.WriteLine("Click()方法被调用后");
await secondHandlerFinished;
}
private static void OnButtonClicked1(object sender, EventArgs e)
{
Console.WriteLine(" 程序1启动中。。。");
Task.Delay(100).Wait();
Console.WriteLine(" 程序1结束");
}
private static async void OnButtonClicked2Async(object sender, EventArgs e)
{
Console.WriteLine(" 程序2启动中。。。");
Task.Delay(100).Wait();
Console.WriteLine(" 程序2异步处理中");
/*await等待Task执行延时0.5秒后输出,也对应“此类方法的任何调用方都必须继续完成,而无需等待调用的异步方法完成。”*/
await Task.Delay(500);
Console.WriteLine(" 程序2结束");
s_tcs.SetResult(true);
}
private static void OnButtonClicked3(object sender, EventArgs e)
{
Console.WriteLine(" 程序3启动中。。。");
Task.Delay(100).Wait();
Console.WriteLine(" 程序3结束");
}
}
// 输出:
//
// 点击按钮,Click()方法被调用前
// 提出请求
// 程序1启动中。。。
// 程序1结束
// 程序2启动中。。。
// 程序2异步处理中
// 程序3启动中。。。
// 程序3结束
// 通知监听器
// 点击按钮,Click()方法被调用后
// 程序2结束
最后再附带一个小技巧:当遇到微软封装好的类/方法不懂怎么使用时,选中它,按F12跳转进去就会看到里面的构造,里面都有解释说明(不出意外都是英文)。