Clone an IEnumerator

HI everyone,

I need to clone an IEnumerator because the original one gets “consumed” after it’s used.

I found a C# Example in this thread(Ben Maddow answer): c# - Is it possible to clone an IEnumerable<T> instance, saving a copy of the iteration state? - Stack Overflow

So I implemeted it this way:

public static T Clone<T>(T source) where T : class, IEnumerator
    {
        var sourceType = source.GetType().UnderlyingSystemType;
        var sourceTypeConstructor = sourceType.GetConstructor(new Type[] { typeof(Int32) });
        var newInstance = sourceTypeConstructor.Invoke(new object[] { -2 }) as T;

        var nonPublicFields = source.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
        var publicFields = source.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
        foreach (var field in nonPublicFields)
        {
            var value = field.GetValue(source);
            field.SetValue(newInstance, value);
        }
        foreach (var field in publicFields)
        {
            var value = field.GetValue(source);
            field.SetValue(newInstance, value);
        }
        return newInstance;
    }

And test to use it this way:

IEnumerator MyMethod ( int para )
{
     print("got=" + para );
     yield return 0;
}

void Start()
{
     IEnumerator clone = Clone( MyMethod(15) );
}

But I get a NullReferenceException : Object not set to an instance of an object at the line:
var newInstance = sourceTypeConstructor.Invoke(new object[ ] { -2 }) as T;

I never used Reflection and I don’t know how to handle this.

And maybe, if by the way there is a solution to clone or create a new instance from the original IEnumerator, I’m okay to hear it.

Thanks in advance guys

EDIT → ANSWER at the bottom of the page from @JohnnyA :

Why are you attempting to clone this enumerator? A new one is created each time you invoke the MyMethod(15).

var enum1 = MyMethod(15);
var enum2 = MyMethod(15);
var enum3 = MyMethod(15);
  1. that method doesn’t have to be generic seeing as you don’t really use the generic for anything. You could just accept IEnumerator as the parameter, and return an IEnumerator.

  2. If you have the function, why not just create a new instance of it by calling the method again? This would effectively be a clone.

  3. Your function appears to be for cloning a generic object by reflecting out and copying its fields (there’s an added issue with the implementation because the reflection done does not account for any private fields of the types this object inherits from… the bindingflags used do not account for those.). This is an issue seeing as the ‘iterator function’ you’re cloning doesn’t really have much for fields representing its state. It’s a bit more complex than that.

  4. Because ‘iterator methods’ do not implement the ‘Reset’ method of the IEnumerator interface (it throw an exception), any clone of an iterator method would a) not get any of the first entries in the enumerator that you have already moved over and b) you’d waste up the enumerator in the cloning process (operating all parts of the code in the iterator method).

tldr; - number 2 is the most important. Why are you even doing this? Just call the method again, a whole new iterator is created.

Actually it works, but I wasn’t specific enough. I actually import my method from a method parameter, and then use it to add a listener to a button click like so:

    IEnumerator MyMethod ( int para )
    {
         print("got=" + para );
         yield return 0;
    }

    void AddAction( IEnumerator myAction )
{
gameObject.GetComponent(Button).onClick.AddListener( delegate() {  StartCoroutine( myAction )  } );
}
    
    void Start()
    {
        AddAction( MyMethod ( 15 ) );
    }

And then, MyMethod is only called at first click;

If I change the delegate for this:
gameObject.GetComponent(Button).onClick.AddListener( delegate() { var tempIEnum = myAction; StartCoroutine( tempIEnum ) } );

I have the same issue!

I don’t see how this has anything to do with your initial question about cloning…

Since the IEnumerator is consumed. I’d like to use the clone in the delegate each time it is called. But, as I said atthr beginning, I’m open to other solutions. The only thing is that I want to preseve the way the Action Method is called: Action ( MyMethod(12) ). And not passing lambdas inside the Action argument.

I see what you want…

Why have the AddAction take the enumerator at all? How about something like this?

    IEnumerator MyMethod ( int para )
    {
         print("got=" + para );
         yield return 0;
    }

    void AddAction(System.Action action)
    {
        gameObject.GetComponent<Button>().onClick.AddListener(action);
    }

    void Start()
    {
        AddAction(() => { StartCoroutine(MyMethod(15)); });
    }

This way add action can dual purpose for general actions, or for actions that start coroutines.

Yep, it would work. But as I said in my previous post I want to keep the simple syntax AddAction( Method(15) ) and put the complex part into the AddAction Method. I know it seems a stubborn way of thinking, but it’s to simplify the repetitive use of AddAction. Even if it’s imply not so efficient way of scripting behind the scene since it’s just call at click and not in update.

If someone have any idea to make it happen, it would definetely make , at least, my month!

As was said before… you can’t clone the enumerator created from an ‘iterator method’. Just can’t be done.

I’m offering you the alternative.

I understand it and apreciate your help. But I can’t imagine that it’s not doable! I mean, the easy way to pass the function. Maybe passing an IEnumerator is not the best way. But I tried everything, passing a Func<IEnumerator, int>, but neither got it to work. I’m stuck on this one for days and now I wait for a messiah. :face_with_spiral_eyes:

Here’s another option. You can create a delegate that represents a coroutine. I do this for other things, and you could use it as well. The delegate is basically this:

public delegate IEnumerator CoroutineMethod();

Your AddAction would look like this then:

void AddAction(CoroutineMethod routine)
{
    gameObject.GetComponent<Button>().onClick.AddListener(() => { routine(); });
}

void Start()
{
    AddAction(this.MyMethod);
}

Downside is that this doesn’t support paramters. What we can do for that is:

Have a generic CoroutineMethod (similar to System.Action with generic inputs)

public delegate IEnumerator CoroutineMethod<T>(T param);
public delegate IEnuemrator CoroutineMethod<T1,T2>(T1 param1, T2 param2);
... so on so forth

And

void AddAction(System.Delegate routine, object[] args)
{
    gameObject.GetComponent<Button>().onClick.AddListener(() => {
        var e = routine.DynamicInvoke(args) as IEnumerator;
        if(e != null) StartCoroutine(e);
    }
}

void Start()
{
    AddAction(new CoroutineMethod<int>(MyMethod), new object[]{15});
}

Really though… I find all these interfaces to be dirty. Where as the nice simple Action based one is a clean interface. I don’t see what’s so not “clean” about:

void Start()
{
    AddAction(() => { MyMethod(15); });
}

It’s pretty straight forward.

2 Likes

Your original question about cloning an IEnumerator that was created from an iterator method… sorry, no, it can not be cloned. It’s not the way that the iterator method works in .net/mono.

Well, I didn’t play wih Delegate passed through method. Interesting. But yep definetely not helping the syntax. Too bad…
And to be clear, I’m not really saying that the use of lambdas is not clean, but not easy to understand regarding the syntax for the beginners, which is what the script I’m trying to do is for.

For now, if I can’t find any other way, which I would prefer not, is to pass as I said, an Func < object, Ienumerator> + a second object argument.

So the call will be something like this : AddAction( MyMethod, 12 ); But this imply defining lots of AddActions with diferents objects like int, float, string, Component, etc.

But yep, as your last post says, the question was about cloning an IEnumerator, and aparently it’s not doable…! Thanks for your help

If you want an in depth reason why… take a look here. This goes over what is actually generated when you compile an iterator method.

http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx

As you can see a special class type is created, and the instance of it is a fairly complex object. The cloning of which is difficult. Especially since the state of it is stored in its fields. So a clone wouldn’t revert back to the start of the enumerator, but instead preserve the current state.

Yep, I’ve been through this post ( Ben Maddox point it out when answering the stackoverflow link I posted ). But as hard as I tried to understand, I didn’t got a fairly bit of anything hapenning here. I’m a self taught young developper and this thing exceeds by far my knowledge!

Note in the delegate example I showed. You could also overload the ‘AddAction’ method with multiple generic types.

void AddAction(CoroutineMethod method);

void AddAction<T>(CoroutineMethod<T> method, T param);

void AddAction<T1, T2>(CoroutineMethod<T1, T2> method, T1 param1, T2 param2);

Still though I find this convoluted. A simple example in the documentation demonstrating how to pass in a coroutine doesn’t seem to hard. It also means that people like me who have a custom ‘RadicalCoroutine’ also have support to. I don’t call Coroutines directly, instead I call an extension method called ‘StartRadicalCoroutine’.

http://jupiterlighthousestudio.com/unity-radical-coroutines/

Thanks for this I’ll look at this. specificaly since it looks usefull for AI implementation. Though, again, and you can throw a rock at me for being stubborn, if I understood it well, user should call your delegate like so AddAction( this.MyMethod, 12);

Which is already to complicated and where I prefere passing a Func<object, IEnumerator> as I showed few messages ago.( where the syntax would be AddAction( MyMethod, 13). Even if I have to define shit loads of different possible parameters type :p.

And for the last thing you pointed out, the flexibility regarding actual user own implements compatibility. The script will defenitely be for beginners and will probably not match the needs of advanced programers!

I tested this code with System.Collections class Stack : ICollection, IEnumerable, ICloneable.

using UnityEngine;
using System.Collections;
 
public class temp : MonoBehaviour {
 
    // Use this for initialization
    void Start () {
 
        // Creates and initializes a new Stack.
        Stack myStack = new Stack();
        myStack.Push("Hello");
        myStack.Push("World");
        myStack.Push("!");
        PrintValues(myStack);
   
    }
 
    void PrintValues( IEnumerable myCollection )  {
 
        Debug.Log("Call 1");
        foreach ( System.Object obj in myCollection ) Debug.Log( (string)obj );
        Debug.Log("Call 2");
        foreach ( System.Object obj in myCollection ) Debug.Log( (string)obj );
 
    }
 
}

And IEnumerator doesn’t get consumed.

That IEnumerable is a Stack, not an iterator method. They’re different beasts all together.

1 Like

This! And it doesn’t really helps regarding what I’m trying to achieve. But thanks for your contribution!