如何对AssetBundle.LoadAssetAsync使用await?非Task类型如何支持await?
Unity中非Task类型异步操作的await实现方案
C# 的 await 关键字并非只能作用于 Task/Task<T> 类型,只要目标类型符合可等待模式:即提供返回符合规范的 awaiter 对象的 GetAwaiter() 方法,就可以被 await 修饰。你代码中的 AssetBundleRequest 属于 Unity 异步操作基类 AsyncOperation 的子类,适配方案如下:
方案1:直接使用Unity官方内置支持
Unity 2018.1 及以上版本默认已经为所有 AsyncOperation 类型(包括AssetBundleRequest、ResourceRequest、场景加载异步句柄等)实现了 GetAwaiter 扩展,只要你满足以下两个条件,你标注//that's wrong的代码其实可以直接正常运行:
- 项目脚本运行时版本设置为 .NET 4.x Equivalent 或更高
- 代码文件引用了
UnityEngine命名空间
方案2:自定义扩展适配低版本/旧运行时
如果你的项目使用的Unity版本低于2018.1,或是仍在使用.NET 3.5兼容运行时,可以自行实现AsyncOperation的可等待扩展,代码如下:
using System.Runtime.CompilerServices; using UnityEngine; using System.Threading.Tasks; public static class AsyncOperationAwaiterExtension { // 适配所有AsyncOperation基础类型的扩展 public static TaskAwaiter GetAwaiter(this AsyncOperation asyncOp) { var tcs = new TaskCompletionSource<object>(); asyncOp.completed += _ => tcs.SetResult(null); return ((Task)tcs.Task).GetAwaiter(); } // 适配AssetBundleRequest带返回结果的泛型扩展 public static TaskAwaiter<AssetBundleRequest> GetAwaiter(this AssetBundleRequest asyncOp) { var tcs = new TaskCompletionSource<AssetBundleRequest>(); asyncOp.completed += _ => tcs.SetResult(asyncOp); return tcs.Task.GetAwaiter(); } }
添加完上述扩展后,你原有代码不需要做任何修改,await req就可以正常执行,等待资源加载完成后才会执行后续逻辑。
修正后的完整代码示例
Task<AssetBundle> request = assetbundles.LoadBundleAsync(bundleName); await request; AssetBundleRequest req = request.Result.LoadAssetAsync<T>(assetPath); await req; // 增加扩展后可以正常工作 return req.asset as T;
注:Unity中的异步操作await完成后默认会回到Unity主线程,不需要额外处理线程上下文切换问题
内容的提问来源于stack exchange,提问作者xcom2000
相关产品推荐
相关产品推荐

