C#:

using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; public sealed class Loader { private readonly IList<ActionObj> _actionObjs; public static Loader Inst { get; } = new Loader(); public EventHandler<ActionEventArgs> LoaderActionInvoked; public EventHandler<double> LoaderActionCompleted; public int Count => _actionObjs.Count; private Loader () { _actionObjs = new List<ActionObj>(); } /// <summary> /// Adds a new action to be invoked. /// </summary> /// <param name="name">Name of the action.</param> /// <param name="action">The action delegate.</param> public void AddAction ( string name, Action action ) => _actionObjs.Add(new ActionObj(name, action, _actionObjs.Count)); /// <summary> /// Invokes the actions stored in the <see cref="_actionObjs"/> collection. /// </summary> public void Execute () { if (Count == 0) { Debug.WriteLine(@"No actions have been added to the loader!"); return; } var sw = new Stopwatch(); var swAction = new Stopwatch(); sw.Start(); foreach (var aObj in _actionObjs) { swAction.Restart(); aObj.Action.DynamicInvoke(); // Invokes the action. LoaderActionInvoked(this, new ActionEventArgs(aObj.Name,aObj.Index)); // Fires an event when the action has been invoked. Debug.WriteLine($@"{aObj.Index}: {aObj.Name} loaded in: {swAction.Elapsed.TotalMilliseconds}ms"); Form1.ActiveForm.Refresh(); // Demo Thread.Sleep(500); // Demo } sw.Stop(); LoaderActionCompleted?.Invoke(this, sw.Elapsed.TotalMilliseconds); } } public sealed class ActionEventArgs : EventArgs { /// <summary> /// Constructs a new ActionEventArgs object /// </summary> /// <param name="name">Name of the action.</param> /// <param name="index">The currently executed action index.</param> public ActionEventArgs ( string name, int index = -1 ) { Name = name; Index = index; } public string Name { get; } public int Index { get; } } internal class ActionObj { public readonly string Name; public readonly Action Action; public readonly int Index; /// <summary> /// Constructs a new ActionObj Object. /// </summary> /// <remarks>You can also use Lambda instead of a method: () => </remarks> /// <param name="name">Name of the Action, not important but nice.</param> /// <param name="action">The action to be invoked.</param> /// <param name="index">The Index of the sequence.</param> public ActionObj ( string name, Action action, int index ) { Name = name ?? throw new ArgumentNullException(nameof(name)); Action = action ?? throw new ArgumentNullException(nameof(action)); Index = index; } }