Executing a list of coroutines at specific times

I would like to be able to execute a list of coroutines at specific times and allow this list to be serialized.

To implement this I thought that I would create a base “Script” class:

public abstract class Script
{
    IEnumerator action;
    float time;

    public Script(ScriptSettings settings)
    {
        time = settings.Time;
    }

    public void Execute()
    {
        float elapsedTime = time - Time.time;

        // Check to see if the script has expired
        if (elapsedTime < 0)
        {
            return;
        }

        OnExecute(elapsedTime);
    }

    protected abstract void OnExecute(float elapsedTime);
}

The derived classes would then have the specific coroutine or “action” which would be called from Execute:

public class Fire : Script
{
    IEnumerator action;
    float time;

    public Fire(ScriptSettings settings)
        : base(settings)
    {

    }

    protected override void OnExecute(float elapsedTime)
    {
        StartCoroutine(Firing(elapsedTime));        // Can't use this function outside of a MonoBehaviour derived class
    }

    IEnumerator Firing(float startTime)
    {
        yield return new WaitForSeconds(startTime);

        // Fire
        Debug.Log("Fire " + Time.time);
    }
}

This method fails to work as I can’t derive from both MonoBehaviour and Script.

What methods do you guys use for executing a list of coroutines at specific times?

It would normally seem straightforward but I will need to serialize each type of coroutine and the time at which it will execute. The time part is easy but I thought the coroutine will require a specific class to which it is associated?

Hmm how about a timer script with a public static method that can register your coroutines and call from your OnExecute?

using System;
using System.Collections.Generic;
using UnityEngine;

public class Timer : MonoBehaviour 
{
	private static Dictionary<Action, float> timers = new Dictionary<Action, float>();

	public static void Set(Delegate callback, float duration, float delay = 0, params object[] parameters)
	{
		if(delay > 0)
		{
			timers.Add(() => timers.Add(() => callback.DynamicInvoke(parameters), duration), delay);
		}
		else
		{
			timers.Add(() => callback.DynamicInvoke(parameters), duration);
		}
	}

	private void Update()
	{
		foreach (KeyValuePair<Action, float> timer in timers)
		{
			if(timer.Value >= 0)
			{
				timers.Remove(timer.Key);
				timer.Key();
			}
			else
			{
				timers[timer.Key] -= Time.deltaTime;
			}
		}
	}
}