- Home /
IEnumerators saving passed value into two different variables.
I'm still fighting windmills trying to create ReplayCoroutine method for my CoroutineManager. My question is mostly based for IEnumerators:
If I pass and IEnumerator in a method
CoroutineNode ReplayCoroutine(CoroutineNode cn)
and have a custom class
public class CoroutineNode
{
public fiber;
public fiberToCopy;
public CoroutineNode(IEnumerator _fiber)
{
this.fiber = _fiber;
this.fiberToCopy = _fiber;
}
public CoroutineNode(CoroutineNode cn)
{
fiber = cn.fiber;
fiberToCopy = cn.fiberToCopy;
}
}
and now when I want to copy I pass not the fiber, but fiberToCopy which then this new CoroutineNode should have IEnumerators that are not iterated yet since its a copy of the original one. Is value of IEnumerator passed by ref or value?
I've read a bunch of stuff on msdn and as I get it most people tend not to fu** with IEnumerators in a way I am trying to do it. Any help is appreciated!
Answer by Huacanacha · Jul 04, 2014 at 01:52 PM
An Interface is a Reference Type and is therefore passed by reference. In your code finer and fiberToCopy will refer to the same object.
You should pass an IEnumerable (a minimal enumerable interface to the underlying collection) then spawn a new IEnumerator whenever you need.
public IEnumerable fiberSource;
public IEnumerator fiberEnumerator;
public CoroutineNode(IEnumerable fiberSource)
{
this.fiberSource = fiberSource;
this.fiberEnumerator = fiberSource.GetEnumerator();
}
public CoroutineNode(CoroutineNode cn) : this(cn.fiberSource)
{}
Edit: per Bunny's comments below you can indeed use IEnumerable (rather than IEnumerator) as the Coroutine return type so you can pass it to the CoroutineNode constructor. It's an interesting use-case... I'm glad this worked for you!
That fairly makes sense but now I'm stuck with the thing that coroutine is IEnumerator and returns such type, how can i pass IEnumerator to constructor and get IEnumerable? Or much better can I implement coroutine so that it returns IEnumerable?
I apologize I'm not very good with generics and iterators
Yes, you can simply change the return type of your coroutine to IEnumerable. That is actually the more used type in the .NET / C# world. An IEnumerator is one instance which is created whenever you call the generator function. An IEnumerable is an object which can generate multiple instances of that IEnumerator.
You just have to call GetEnumerator of your IEnumerable to get an IEnumerator. This one can be passed to StartCoroutine.
An IEnumerator can't be duplicated.
ps: I've never tried using IEnumerable as a coroutine, only for "normal" IEnumerables ;) But i think it should work.
Interesting. I wasn't aware you could use IEnumerable type for a Coroutine method. If I can test this or find definitive information I'll add it to the answer.
Also btw, if you are purely using this for Coroutines don't worry about using Generics.
Those "Coroutine methods" are actually a C# language feature and nothing added by Unity. They are called generator methods in general but also iterators (which microsoft prefers).
The real magic happens in the compiler as it turns your code inside that function into a state machine and wraps everything into an internal class. When you use IEnumerator as return type, the generator method returns an instance of that internal class. If you use IEnumerable as return type, the compiler creates two classes. The first is similar to the class you would get with IEnumerator, the second is a "wrapper" class which only works as closure for the parameters and provides (according to the IEnumerable interface) the GetEnumerator method which can create an instance of the interator with the original passed parameters.
That's also the reason why you can't use "ref" or "out" parameters for such methods since those can't be "stored" in the class.
There used to be a great blog post about how generators work internally by Fernando Zapata, the author of the CoroutineScheduler, but unfortunately his blog got "wiped out"
Thank you guys for explaining this stuff to me. I know get it how this works and get the picture what should I do, and I've made this thing work. I'll tag Huacanacha solution as answer although all of you guys contributed to this.
Cheers! :)