using System; using System.Collections.Generic; using System.Linq; using System.Text; using Chernobyl.Utility; namespace Chernobyl { /// <summary> /// Combines the invocation of two methods into one method. This type will /// invoke the method passed to its constructor when both <see cref="First(T1)"/> /// and <see cref="Second(T2)"/> have been invoked. /// </summary> /// <typeparam name="T1">The argument type of <see cref="First(T1)"/>.</typeparam> /// <typeparam name="T2">The argument type of <see cref="Second(T2)"/>.</typeparam> public class ActionCombiner<T1, T2> { /// <summary> /// Initializes a new instance of the <see cref="ActionCombiner{T1, T2}"/> class. /// </summary> /// <param name="action">The method that is to be invoked once /// <see cref="First(T1)"/> and <see cref="Second(T2)"/> have both been /// invoked.</param> public ActionCombiner(Action<T1, T2> action) { action.ThrowIfNull("action"); _action = action; } /// <summary> /// An <see cref="Action{T1}"/> method that must be invoked for the main /// <see cref="Action{T1, T2}"/> to be invoked. /// </summary> /// <param name="first">The argument that is to be passed to the /// <see cref="Action{T1, T2}"/> method.</param> public void First(T1 first) { _first = first; _methodsInvoked[(int)Method.First] = true; // If the second method has been invoked, invoke _action. if (_methodsInvoked[(int)Method.Second]) _action(_first, _second); } /// <summary> /// An <see cref="Action{T1}"/> method that must be invoked for the main /// <see cref="Action{T1, T2}"/> to be invoked. /// </summary> /// <param name="second">The argument that is to be passed to the /// <see cref="Action{T1, T2}"/> method.</param> public void Second(T2 second) { _second = second; _methodsInvoked[(int)Method.Second] = true; // If the first method has been invoked, invoke _action. if (_methodsInvoked[(int)Method.First]) _action(_first, _second); } /// <summary> /// The method that is to be invoked once <see cref="First(T1)"/> and /// <see cref="Second(T2)"/> have both been invoked. /// </summary> readonly Action<T1, T2> _action; /// <summary> /// The argument that was passed to <see cref="First(T1)"/> when it was /// invoked. <c>default(T1)</c> if <see cref="First(T1)"/> has not yet /// been invoked. /// </summary> T1 _first; /// <summary> /// The argument that was passed to <see cref="Second(T2)"/> when it was /// invoked. <c>default(T1)</c> if <see cref="Second(T2)"/> has not yet /// been invoked. /// </summary> T2 _second; /// <summary> /// Flags for which methods have been invoked. The <see cref="First(T1)"/> /// is the first index, <see cref="Second(T2)"/> is the second index. If /// a value is true then that method has been invoked, false if otherwise. /// </summary> readonly bool[] _methodsInvoked = new bool[(int)Method.Count]; /// <summary> /// The indices of the method flags in <see cref="_methodsInvoked"/>. /// </summary> enum Method { /// <summary> /// The index of <see cref="ActionCombiner{T1, T2}.First(T1)"/>. /// </summary> First, /// <summary> /// The index of <see cref="ActionCombiner{T1, T2}.Second(T2)"/>. /// </summary> Second, /// <summary> /// Number of items in this enum. /// </summary> Count } } /// <summary> /// Combines the invocation of two methods into one method. This type will /// invoke the method passed to its constructor when <see cref="First(T1)"/>, /// <see cref="Second(T2)"/>, and <see cref="Third(T3)"/> have been invoked. /// </summary> /// <typeparam name="T1">The argument type of <see cref="First(T1)"/>.</typeparam> /// <typeparam name="T2">The argument type of <see cref="Second(T2)"/>.</typeparam> /// <typeparam name="T3">The argument type of <see cref="Third(T3)"/>.</typeparam> public class ActionCombiner<T1, T2, T3> { /// <summary> /// Initializes a new instance of the <see cref="ActionCombiner{T1, T2}"/> class. /// </summary> /// <param name="action">The method that is to be invoked once /// <see cref="First(T1)"/>, <see cref="Second(T2)"/>, and /// <see cref="Third(T3)"/> have both been invoked.</param> public ActionCombiner(Action<T1, T2, T3> action) { action.ThrowIfNull("action"); _action = action; } /// <summary> /// An <see cref="Action{T1}"/> method that must be invoked for the main /// <see cref="Action{T1, T2, T3}"/> to be invoked. /// </summary> /// <param name="first">The argument that is to be passed to the /// <see cref="Action{T1, T2, T3}"/> method.</param> public void First(T1 first) { _first = first; _methodsInvoked[(int)Method.First] = true; // If the second method has been invoked, invoke _action. if (_methodsInvoked[(int)Method.Second] && _methodsInvoked[(int)Method.Third]) _action(_first, _second, _third); } /// <summary> /// An <see cref="Action{T1}"/> method that must be invoked for the main /// <see cref="Action{T1, T2, T3}"/> to be invoked. /// </summary> /// <param name="second">The argument that is to be passed to the /// <see cref="Action{T1, T2, T3}"/> method.</param> public void Second(T2 second) { _second = second; _methodsInvoked[(int)Method.Second] = true; // If the first method has been invoked, invoke _action. if (_methodsInvoked[(int)Method.First] && _methodsInvoked[(int)Method.Third]) _action(_first, _second, _third); } /// <summary> /// An <see cref="Action{T1}"/> method that must be invoked for the main /// <see cref="Action{T1, T2, T3}"/> to be invoked. /// </summary> /// <param name="third">The argument that is to be passed to the /// <see cref="Action{T1, T2, T3}"/> method.</param> public void Third(T3 third) { _third = third; _methodsInvoked[(int)Method.Third] = true; // If the first method has been invoked, invoke _action. if (_methodsInvoked[(int)Method.First] && _methodsInvoked[(int)Method.Second]) _action(_first, _second, _third); } /// <summary> /// The method that is to be invoked once <see cref="First(T1)"/> and /// <see cref="Second(T2)"/> have both been invoked. /// </summary> readonly Action<T1, T2, T3> _action; /// <summary> /// The argument that was passed to <see cref="First(T1)"/> when it was /// invoked. <c>default(T1)</c> if <see cref="First(T1)"/> has not yet /// been invoked. /// </summary> T1 _first; /// <summary> /// The argument that was passed to <see cref="Second(T2)"/> when it was /// invoked. <c>default(T1)</c> if <see cref="Second(T2)"/> has not yet /// been invoked. /// </summary> T2 _second; /// <summary> /// The argument that was passed to <see cref="Third(T3)"/> when it was /// invoked. <c>default(T1)</c> if <see cref="Third(T3)"/> has not yet /// been invoked. /// </summary> T3 _third; /// <summary> /// Flags for which methods have been invoked. The <see cref="First(T1)"/> /// is the first index, <see cref="Second(T2)"/> is the second index. If /// a value is true then that method has been invoked, false if otherwise. /// </summary> readonly bool[] _methodsInvoked = new bool[(int)Method.Count]; /// <summary> /// The indices of the method flags in <see cref="_methodsInvoked"/>. /// </summary> enum Method { /// <summary> /// The index of <see cref="ActionCombiner{T1, T2, T3}.First(T1)"/>. /// </summary> First, /// <summary> /// The index of <see cref="ActionCombiner{T1, T2, T3}.Second(T2)"/>. /// </summary> Second, /// <summary> /// The index of <see cref="ActionCombiner{T1, T2, T3}.Third(T3)"/>. /// </summary> Third, /// <summary> /// Number of items in this enum. /// </summary> Count } } }