The yield statement cannot be used inside anonymous method blocks?

Trying to make a UI panel appear then disappear 2 seconds after popping up. I am getting this error in the title and have no clue what it means and how to fix it. Can someone please explain how yield works?

using UnityEngine;
using System.Collections;
using GooglePlayGames;
using UnityEngine.SocialPlatforms;

public class GooglePlay : MonoBehaviour {
	public GameObject  FailedLogin;
	public GameObject  SuccessLogin;

	void Awake () {

		DontDestroyOnLoad (transform.gameObject);
	}

	// Use this for initialization
	void Start () {

	}
	
	// Update is called once per frame
	void Update () {
	
	}


void LogIn () {
		// authenticate user:
		Social.localUser.Authenticate((bool success) => {
			// handle success or failure
			if (success)
			{
				Debug.Log ("Successfully logged in");
				SuccessLogin.active = true;
				yield return new WaitForSeconds (2);
				SuccessLogin.active = false;
			}
			else
			{
				Debug.Log ("Log in failed");
				FailedLogin.active = true;
				yield return new WaitForSeconds (2);
				FailedLogin.active = false;

			}
			
		});
	}
}

Yield can be used in any method, including anonymous ones (Edit: At least in Boo) . I use this technique very often for various enumerable generators. The problem is that yield and unity coroutines are not the same thing.

Yield turns any method you use the keyword in to a generator. Calling the “method” will actually consturct an enumerable object. Iterating over it will always cause the part of its code to be executed, and the yielded value be returned as Current. Example (i write in Boo, sorry :slight_smile: ):

/// anonymous method with an array of int as input, enumerable of int as output
/// this generator will yield any value from the input array that is even.
getEvenInts = def( input as (int) ) as IEnumerable[of int]:
    for val in range(input.Length):  //for in boo is like foreach in c# i think
        print("testing $val")
        if val%2 == 0:
            yield val

///
for num in getEvenInts((1,2,3,4,5,6,7,8,9,10)):
    print("$num is even")

Iterating over getEvenInts will always execute bit of code until it hits yield. Then the control returns to the cycle (print the value), then again continue in generator code from the last yield.
The print out will be:

testing 1
testing 2
2 is even
testing 3
testing 4
4 is even
......

Notice the order of prints. It’s not all testing prints and then all “is even” prints, it jumps in and out.

Now you understand how generators and yield work, you can try to understand unity coroutines, it’s quite simple.

When you call StartCoroutine(), you give it the enumerator as argument. Unity will do the first iteration over it (executing part of the code) and read the yielded value. When unity receives one of the values like WaitForSeconds, it will save the enumerator in an internal queue, remembering when it should continue. Every next frame after, unity checks the queue for enumerators that should be continued. After the time passed and the check returns true, unity simply iterates over the enumerator once again, repeating the procedure until the enumerator ends (just like the foreach cycle ends when there are no more objects in the array).

Now to find out why your code doesn’t work.
First, i just realized that maybe the first compilation problem is that c# actually doesn’t support yield in anonymous methods :slight_smile: Boo is OK with that. That problem you can fix by removing the anonymous methods and making it your class member methods (again i am no expert in c#, but i believe the => arrow pointing to a {} code block is responsible, try to point the arrow to a member method name?

This will fix the compilation error, though your coroutine will still not work. At least it does’nt say in the docs that the callback from Authenticate() “can be a coroutine” which would mean the unity will detect if the method is a generator and start the coroutine for you.

Unity won’t react to WaitForSeconds unless the generator is iterated over from the unity engine, being started by StartCoroutine call. To fix this, you need:

  • A member method to be used as coroutine. Just copy the code from the block after => lambda assignment and make it a separate (non anonymous) method.

    void AuthenticationCallback(bool success)
    {
    if (success)
    {
    Debug.Log (“Successfully logged in”);
    SuccessLogin.active = true;
    yield return new WaitForSeconds (2);
    SuccessLogin.active = false;
    }
    else
    {
    Debug.Log (“Log in failed”);
    FailedLogin.active = true;
    yield return new WaitForSeconds (2);
    FailedLogin.active = false;

              }
    

    }

  • To start the coroutine. So where the original anonymous method was, replace it with

    => { StartCoroutine(AuthenticationCallback(success)) }

Now you\ve created an anonymous method that tells the monoBehaviour to start the coroutine, passing the argument to it as well. The generator method *the one using yield) is correctly iterated over by the unity engine and WaitForSeconds are received by the engine.

I hope i clarified the problem to you

yield can be used within the Coroutine you can not used in the methods…

see the link below you will understand it better…