c# - 如何使用自定义 IEnumerator 类生成协程
问题描述
我在 Unity 中找到了用于异步加载模型的代码。我想知道它是如何工作的,所以我可以做一些类似的事情来运行一个异步函数并在协程中从中检索一个值。我在网上找不到任何使用相同结构的东西,但我可能不知道要搜索什么,我认为这个示例没有使用异步流。
我感兴趣的代码是:
IEnumerator Start()
{
AssetBundleCreateRequest bundleLoadRequest = AssetBundle.LoadFromFileAsync(pathToBundle);
yield return bundleLoadRequest;
AssetBundle myLoadedAssetBundle = bundleLoadRequest.assetBundle;
...
}
我不确定什么样的对象“AssetBundleCreateRequest”是用异步函数初始化的,在协程中产生,然后能够在协程继续时提取属性。我想在协程中运行我自己的异步函数,并在它完成后从中提取返回值。
解决方案
在内部,Unity 只是在异步加载任务完成之前每帧IEnumerator
创建一个。yields
你可以例如做类似的事情
public static IEnumerator WaitUntilIsDoneAsync(Action action)
{
var task = task.Run(() => action?.Invoke());
while (!task.IsCompleted)
{
yield return null;
}
}
然后你可以等待一些长时间的异步东西通过例如完成
yield return WaitUntilIsDoneAsync(() =>
{
Thread.Sleep(3000);
}
当然,为了使它更有用,您可能更愿意像他们那样实现一个类,您还可以在其中存储任务结果以供以后访问等。
当然,这在很大程度上取决于您希望返回的类型。
例如,它可能看起来像这样。请注意,我不是异步专家,并且从空中抓住这个例子..不知道它是否完全像那样工作,但只是解释在后台或多或少发生了什么。
所以为了yield
你只需要any IEnumerator
,它不必通过StartCoroutine
.
所以你可以通过实施来实现IEnumerator
public class AsyncFileLoadRequest : IEnumerator
{
private readonly object _contentLock = new object();
private Task<string> asyncLoadingTask;
public string File content
{
get
{
lock(_contentLock)
{
return _fileContent;
}
}
}
public AsyncFileLoadRequest(string path)
{
asyncLoadTask = File.ReadAllTextAsync(path);
AwaitTaskAsync();
}
#region IEnumerator implementation
object IEnumerator.Current => null;
public void Reset() { }
public bool MoveNext()
{
// As long as this returns true the coroutine will wait
return !asyncLoadTask.IsCompleted;
}
#endregion IEnumerator implementation
private async void AwaitTaskAsync()
{
lock(_contentLock)
{
_fileContent = await asyncLoadTask;
}
}
}
所以你可以做类似的事情
var request = new AsyncFileLoadRequest(filePath);
yield return request;
var content = request.FileContent;
或者像他们一样使用工厂方法:
public static class FileIOStuff
{
public static AsyncFileLoadRequest LoadFileAsync(string path)
{
return new AsyncFileLoadRequest (path);
}
}
就像这样称呼它
var request = FileIOStuff.LoadFileAsync (filePath);
yield return request;
var content = request.FileContent;
推荐阅读
- google-sheets - 如果单元格为空白,则 Google 表格功能将文本添加到另一个单元格
- reactjs - 反应错误:无效的钩子调用 - 即使语法似乎正确
- docker - 为 jupyter spark notebook 构建 docker 映像时出错
- java - 按可用 ID 单击元素
- openssl - 由于 openssl 无法编译 cpython 3.11.0
- regex - .htaccess:允许使用正则表达式访问以字母“r”开头的目录
- javascript - 如何在 JavaScript 中的 UL 的每个文本节点之间添加换行符?
- c# - 我不知道为什么 addForce 在fixedUpdate 中不起作用。虽然它在正常更新中工作
- flutter - Flutter Cubit:获取存储变量的好方法?
- javascript - 日期差异 (UNIX)