参考自这篇文章:
总结下来,就是我们没有进行异步等待时,产生的异常将被视为开放异常,并且因为没有进行等待这个任务完成,则就无法捕获异步任务中的异常,在这种情况下,当 GC 运行时,它将被视为开放异常,,此时才有可能抛出(实测异常发生后很久untiy也没有捕获到异常日志)
在异步上下文中,使用try-catch捕获
using System;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class Example : MonoBehaviour
{
private async void Start()
{
// 例外の内容のエラーログが出力される
// try-catchでハンドリングできる
await SomeProcessAsync();
}
private async UniTask SomeProcessAsync()
{
await UniTask.RunOnThreadPool(() => throw new Exception("ExampleException"));
}
}如下情况,将视为开放异常,基本上unity不会捕获到异常信息。
using System;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class Example : MonoBehaviour
{
private async void Start()
{
// try-catchできない
// GCのタイミングで例外が出力される
SomeProcessAsync().Forget();
}
private async UniTask SomeProcessAsync()
{
await UniTask.RunOnThreadPool(() => throw new Exception("ExampleException"));
}
}解决方案
有两种解决方案,只测试后附加回调,另一种请自行测试。
修改
UniTaskScheduler.UnobservedExceptionWriteLogType日志等级,便于发生异常时直接在unity日志上输出对应等级错误提醒
using System;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class Example : MonoBehaviour
{
private async void Start()
{
UniTaskScheduler.UnobservedExceptionWriteLogType = LogType.Warning;
// try-catchできない
SomeProcessAsync().Forget();
}
private async UniTask SomeProcessAsync()
{
await UniTask.RunOnThreadPool(() => throw new Exception("ExampleException"));
}
}现在,将打印一条警告,并显示一条消息, UnobservedTaskException: System.Exception: ExampleException 例如“当发生未处理的异常时”。

添加注册一个处理回调,这个也是比较推荐的做法
using System;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class Example : MonoBehaviour
{
private async void Start()
{
// 未処理例外のハンドリング処理を書き換える
UniTaskScheduler.UnobservedTaskException += HandleUnobservedTaskExceptions;
SomeProcessAsync().Forget();
}
private async UniTask SomeProcessAsync()
{
await UniTask.RunOnThreadPool(() => throw new Exception("ExampleException"));
}
private static void HandleUnobservedTaskExceptions(Exception ex)
{
Debug.LogError("未処理例外発生: " + ex);
}
}可以看到回调的内容得到了体现。
同时本方法可以放在.Forget(); 作为参数传递,即.Forget(HandleUnobservedTaskExceptions);
评论