如何解决组合迭代器方法时避免复制大型结构参数
我有一个从分析中得知的大型结构,复制起来很昂贵。我正在使用 in
关键字传递这个结构的实例,效果很好。
现在我想将此作为参数传递给迭代器方法,该方法本身将值传递给其他迭代器方法 - 但不允许使用 in
,这意味着每次传递给方法时都会复制该值.
这里的上下文是一个包含视频游戏保存状态的结构体,迭代器方法是一个“加载”方法,它在 Unity 游戏引擎(它使用迭代器实现协程)中将保存数据的处理分布在多个帧上.加载方法比较复杂,需要分解为多种方法。
示例:
struct SaveData{
// large data
}
// Async loading - can spread processing across frames (yay!) but copies lots of data (boo!)
IEnumerator LoadAsync(SaveData saveData) {// wish I Could use 'in' here!
// use some part of saveData
yield return;
// use more of saveData
yield return InnerLoad(saveData); // wish I Could use 'in' here!
}
IEnumerator InnerLoadAsync(SaveData saveData) {// wish I Could use 'in' here!
// use saveData
yield return;
}
// Synchronous loading - very efficient (yay!) but blocks,causing an unacceptably long delay (boo!)
void LoadSynchronous(in SaveData saveData){
// use some part of saveData
// use more of saveData
InnerLoadSynchronous(in saveData);
}
void InnerLoadSynchronous(in SaveData saveData){
// use saveData
}
我理解为什么通常 in
不允许用于迭代器(例如,如果迭代器/协程比值的所有者更持久呢?) - 所以我可以理解为什么最外层迭代器函数需要一个副本。但是对于内部调用,由于它们是用 yield return
调用的,因此内部迭代器不会比内部迭代器更持久,因此似乎应该有某种方法可以使用 in
。
这里是否有我遗漏的任何语言功能,或者我可以使用一个很好的模式来解决它?我认为用外部类包装类型会起作用,但它看起来有点混乱,当然仍然需要一个副本,因为我不能有 ref
或 in
成员。
解决方法
但是对于内部调用,由于它们是通过 yield return 调用的,因此内部迭代器不会比内部迭代器更持久,因此似乎应该有某种方法可以使用。
你错过了一些东西。举个简单的例子:
public class C
{
public static void Main()
{
var enumerator = Outer(3);
Console.WriteLine("Enumerating 1");
enumerator.MoveNext();
Console.WriteLine("Enumerating 2");
enumerator.MoveNext();
var innerEnumerator = (IEnumerator)enumerator.Current;
Console.WriteLine("Enumerating Inner 1");
innerEnumerator.MoveNext();
}
public static IEnumerator Outer(int i)
{
yield return null;
Console.WriteLine("Yielding Inner");
yield return Inner(i);
}
public static IEnumerator Inner(int i)
{
Console.WriteLine($"Inner {i}");
yield break;
}
}
打印:
Enumerating 1
Enumerating 2
Yielding Inner
Enumerating Inner 1
Inner 3
(SharpLab).
如您所见,Inner
并未立即枚举。 Inner
的编译器生成的实现将编译器生成的 IEnumerable
返回给 Outer
的调用者,直到调用者显式调用 MoveNext
Inner
被执行。
但是,Inner
被调用得更早。编译器生成的 Inner
实现完全执行,并返回生成的 IEnumerator
,就在上面的 Yielding Inner
之后。所以 Inner
需要将变量 i
存储在编译器生成的类中的某处,这就是它不能是 in
的原因。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。