通过CancellationToken ctk控制的异步方法,你可以取消任务,但是当取消任务的时候,系统会报一个异常,你需要准确识别并捕获它,而不是笼统的使用catch (Exception e){} 来捕获。
特别是当流程需要【上一步】【下一步】操作的时候,你取消了当前步骤,那么就要做好try catch的收尾工作。
一、异步方法里面常见的异常类型
- OperationCanceledException ——任务被取消:比如点击了【跳步骤】的按钮
- TimeoutException ——任务超时:比如联网加载资源,网络被墙
- NullReferenceException ——空引用:比如场景都跳转,你没有停止任务,还在继续访问一个slider的值
- Exception ——其它未知异常
二、处理思路
精确捕获各种异常,分门别类的处理,不要笼统的用Exception类型来处理,有的异常,你需要层层外抛,而不是藏着掖着。
try
{
await UniTask.Delay(100,cancellationToken:ctk);
await asyncTaskFlow.FlowAsync(ctk);
}
catch (OperationCanceledException e)
{
Debug.Log($"任务被取消:{e.Message}");
}
catch (TimeoutException e)
{
Debug.LogError($"超时:{e.Message}");
}
catch (NullReferenceException e)
{
Debug.LogError($"空引用: {e.Message}");
}
catch (Exception e)
{
Debug.LogError($"未知异常: {e}");
}
}
三、处理方法
我是嵌套调用的,为了跟踪和精细处理,原始错误层层外抛
/// <summary>
/// 自身旋转
/// </summary>
/// <param name="ctk"></param>
/// <returns></returns>
public async UniTask FlowAsync(CancellationToken ctk)
{
try
{
FlowStatusEvent.RaiseStatusChanged(instanceID, FlowStatus.Running);
Debug.Log($"~~启动Rotate() {Time.realtimeSinceStartup}");
await target.DoRotate(axis, () => speed, duration, ctk, restored);
Debug.Log($"~~结束Rotate() {Time.realtimeSinceStartup}");
FlowStatusEvent.RaiseStatusChanged(instanceID, FlowStatus.Completed);
}
catch (OperationCanceledException e)
{
Debug.Log($"{this_name}任务被取消:{e.Message}");
FlowStatusEvent.RaiseStatusChanged(instanceID, FlowStatus.Canceled);
throw;//层层上抛,让外面去捕获
}
catch (Exception e)
{
Debug.Log($"{this_name}任务异常:{e.Message}");
FlowStatusEvent.RaiseStatusChanged(instanceID, FlowStatus.Failed);
throw;//层层上抛,让外面去捕获
}
}
四、throw与throw new
- 茴香豆的两个写法
throw new Exception() //抛出一个新的异常
throw; //抛出原始异常
- 常见用法:
catch (Exception e)
{
Debug.Log($"{this_name}任务异常:{e}");
throw new Exception() //抛出一个新的异常
throw; // 保留原始异常
}
- 有何区别:
原始异常保留
stack trace 保留
token 保留
调试不会痛苦

1025

被折叠的 条评论
为什么被折叠?



