The main thing is that:
- StartCoroutine simply accepts a parameter of type IEnumerator.
- When you execute MyMethod(), it returns an object of type IEnumerator.
So you are actually not passing just a reference of MyMethod to StartCoroutine, you are actually immediately executing MyMethod, and then passing the value that was returned by the method to StartCoroutine.
IEnumerator enumerator = MyMethod(1, 2); // My method gets executed immediately here
StartCoroutine(enumerator); // You pass the object returned by it to StartCoroutine
The confusing part is that when you write an IEnumerator method in C#, the compiler actually does a bunch of magic behind-the-scenes and generates a whole new class.
Given a coroutine like this:
public IEnumerator MyMethod(int parameter1, int parameter2)
{
Debug.Log("Step " + parameter1);
yield return new WaitForSeconds(1f);
Debug.Log("Step " + parameter2);
}
The compiler would generate something like this:
class MyMethodEnumerator : IEnumerator
{
int parameter1;
int parameter2;
int step;
public object Current { get; private set; }
public bool MoveNext()
{
if(step == 0)
{
Console.WriteLine(string.Concat("Step ", parameter1.ToString()));
Current = new WaitForSeconds(1f);
step = 1;
return true;
}
if(step == 1)
{
step = -1;
Console.WriteLine(string.Concat("Step ", parameter2.ToString()));
return false;
}
return false;
}
}
And when you execute MyMethod(), actually, an instance of this compiler-generated type gets returned.
public IEnumerator MyMethod(int parameter1, int parameter2)
{
return MyMethodEnumerator() { parameter1: parameter1, parameter2: parameter2 };
}
It is with the help of this compiler generated type that coroutines are able to do their thing, where all their code does not get executed at once, but in smaller chunks, separated by yield
statements.
Unity can use the generated object to do something like this essentially:
public static void StartCoroutine(IEnumerator routine)
{
while(routine.MoveNext())
{
if(routine.Current is WaitForSeconds waitForSeconds)
{
Debug.Log("Waiting for "+waitForSeconds.seconds+ " seconds...");
}
}
}
SharpLab example.