I'm trying to serialize/deserialize an IEnumerator generated from a function using yield. I would like to serialize the IEnumerator at any iteration, I don't want to force it to generate all of it values.
I know that the yield keyword generate a class behind the scene, and that why I'm using it, to avoid manually writing iterator, and also to make the code cleaner.
My goal is to make a small game engine similar to Nick Gravelyn - The magic of yield, where each GameElement generate an iterator about his behavior, allowing the programmer to easily control timings (because the iterator allow to interrupt and continue a script). I want to try to add a multiplayer layer on top of that, that why I need to serialize/deserialize an IEnumerator.
Forcing the IEnumerator to generate all of his values also force the game to update, this should be avoided.
My first tentative was somethings like :
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); // crash because interface
while (f.MoveNext());
}
}
}
But deserializing an interface (IEnumerator<int>) is illegal, we need to know the Type of the object behind IEnumerator<int>.
Since the type is generated by the compiler, I try to use reflection over the Deserialize method in order to call it with the correct type generated by the function CountTo() (SerializeTest.Program+<CountTo>d__0 if you are curious)
So my second tentative was somethings like :
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); // still crash
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()) ;
}
}
}
but it still crash when calling JsonSerializer.Deserialize() even if the type is now correct and not an interface.
(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.'
)
The format don't have any importance (json, xml...) as long as it is possible to send it to another computer and deserialize it back.
I naively hope that there is a way to Serialize/Deserialize an IEnumerator because a lot of cool stuff can be done with it, although I have some serious doubts about such a things to be possible.
Thank for reading so far.