Using ref parameters to keep code generic

Good day,

For my generic dialog (yes/no, input check, loading progress) I’m looking for a dynamic way of creating a loading action (UI is covered and working).

But I’m stuck with the loading part. I wrote an coroutine to check if the timeout/requirements have been met, and if so run the action (endaction/timeoutaction).

This way, I can use the dialog for multiple calls. But it seems a coroutine wont accept a ref parameter, so it more or less ‘restricts’ me to use a local/class variable which i want to keep dynamic.

I have wrote a function:

public class ModalHandler : MonoBehaviour {
	private bool boolToCheck;

public void ModalLoad(ref bool valueToCheck, string loadingText, UnityAction startAction, UnityAction endAction, UnityAction timeOutAction, float timeOut){
this.boolToCheck = valueToCheck;

	StartCoroutine (checkLoading(startAction, endAction, timeOutAction, timeOut));
	Debug.Log ("Code goes on!");
}

IEnumerator checkLoading(UnityAction startAction, UnityAction endAction, UnityAction timeOutAction, float timeOut){
	// call the start action
	startAction.Invoke();

	// check if we run into the timeout
	float timer = 0f;
	while (timer <= timeOut) {
		if (boolToCheck) {				// the check variable has been set to true!

			// the condion has been met run the action and close this window
			endAction.Invoke ();
			ClosePanel ();
			yield break;
		}
		timer += 1f;
		yield return new WaitForSeconds (1);
	}

	// the timeout has been reached	
	timeOutAction.Invoke ();
	ClosePanel ();
	yield break;
}

So when i call the ModalLoad. I want to be able to supply a ref bool, instead of a fixed value. So i can use it with any boolean in my game. But when i copy the ref input to a local bool it loses its reference. And i cannot pass the reference into the coroutine, because thats not allowed.

Any light/help on this matter would be much welcome!

ref or out parameters are actual pointers to the memory location of the variable. If you pass a variable as ref parameter it’s memory location get pinned so it can’t be moved around by the memory manager. However this pinning is only valid for the current scope of the execution. ref parameters can’t be “stored” in a variable. They can only be passed on to nested methods and have to be used inside the scope of the current execution.

Coroutines are not methods. The parameters you pass to a coroutine as well as most local variables inside the method actually become member variables of a compiler generated class. Since you can’t store a ref parameter inside a variable ref and out parameters are not allowed at all for coroutines (iterator blocks).

What you need is an actual reference type which you can simply pass to the method. One way is to use a delegate and pass your “variable” as lambda closure.

public void ModalLoad(System.Func<bool> aValueToCheck)
{
    if (aValueToCheck())
        // do something
}

Since “aValueToCheck” is a reference type you can pass it on to your coroutine and use it inside your coroutine. You would call your method like this:

ModalLoad(()=>someVariable);

Of course this only gives you “read” access to the variable. If you need read and write access you have to use two delegates

public void ModalLoad(System.Func<bool> aValueToCheck, System.Action<bool> aValueToSet)
{
    aValueToSet(true);
    // [ ... ]

And call it like this:

ModalLoad(()=>someVariable, (v)=>someVariable=v);