C#如何序列化/反序列化yield函数生成的IEnumerator?
序列化编译器生成的yield迭代器(IEnumerator)问题
需求说明
- 需要实现yield关键字生成的IEnumerator的序列化与反序列化,要求能在任意迭代阶段保存状态,不能强制生成所有迭代值(避免触发不必要的游戏更新逻辑)
- 核心目标是开发类似Nick Gravelyn《The magic of yield》的小型游戏引擎:每个GameElement通过迭代器描述行为,实现脚本的中断与续跑;现在要为引擎添加多人联机层,因此需要跨机器传输迭代器的状态
首次尝试:直接序列化接口
尝试直接用System.Text.Json序列化迭代器,代码如下:
using System; using System.Collections.Generic; using System.Text.Json; namespace SerializeTest { class Program { public static IEnumerator<int> CountTo(int end) { for(int i = 1; i <= end; i++) { Console.WriteLine("i = " + i); yield return i; } } static void Main(string[] args) { IEnumerator<int> e = CountTo(5); string json = JsonSerializer.Serialize(e); Console.WriteLine(json); var f = JsonSerializer.Deserialize<IEnumerator<int>> (json); // 崩溃:无法反序列化接口 while (f.MoveNext()); } } }
问题:反序列化时直接崩溃,因为IEnumerator<int>是接口,序列化器无法实例化接口类型。
第二次尝试:通过反射指定编译器生成的具体类型
已知yield会由编译器生成匿名类(比如SerializeTest.Program+<CountTo>d__0),尝试通过反射获取该类型并调用泛型反序列化方法,代码如下:
using System; using System.Collections.Generic; using System.Reflection; using System.Text.Json; namespace SerializeTest { class Program { public static IEnumerator<int> CountTo(int end) { for(int i = 1; i <= end; i++) { Console.WriteLine("i = " + i); yield return i; } } public static T Deserialize<T>(string json) => JsonSerializer.Deserialize<T>(json); // 依然崩溃 static void Main(string[] args) { IEnumerator<int> e = CountTo(5); string json = JsonSerializer.Serialize(e); Console.WriteLine(json); Type eType = e.GetType(); MethodInfo method = typeof(Program).GetMethod("Deserialize"); MethodInfo genericMethod = method.MakeGenericMethod(eType); object fObj = genericMethod.Invoke(null, new object[] { json }); var f = (IEnumerator<int>)fObj; while (f.MoveNext()) ; } } }
错误信息:
System.InvalidOperationException : 'Each parameter in constructor 'Void .ctor(Int32)' on type 'SerializeTest.Program+<CountTo>d__0' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. The match can be case-insensitive.'
问题:编译器生成的迭代器类的构造函数参数无法与序列化后的属性/字段对应绑定,导致反序列化失败。
后续需求
- 序列化格式不限(JSON、XML等均可),只要能跨机器传输并恢复迭代器状态
- 希望找到可行的实现方案,哪怕可行性较低
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

