internal override void End() { OnEnd(); var finalState = FinalState; Debug.Assert(!InFinalState && (FinalStatesMask & finalState) > 0); // Final state must be assigned before triggering conditions, because they will use it // to determine whether or not undo the events they control. SetFinalState(finalState); // if (_callbacks != null) { // Debug.Assert(_callbacks.Count > 0); // Assert above is potentially false, since the user may call // Clear on _callbacks, as it is an ICollection. foreach (var callback in _callbacks) { callback(this as TEv); } _callbacks = null; } // Following piece of code is optimezed for cases in which an event // belongs to a single event, which represents the great majority of situations. if (Conditions != null) { Debug.Assert(Conditions.Count > 0); // Triggers all conditions to which this event belongs. IParentCondition condition; if (Conditions.Count == 1 && !(condition = Conditions.First).Succeeded) { condition.Trigger(this); } else { var en = Conditions.GetEnumerator(); while (en.MoveNext()) { if (!(condition = en.Current).Succeeded) { condition.Trigger(this); } } } Conditions = null; } // Following piece of code is optimezed for cases in which an event // is "yielded" by a single process, which represents the great majority of situations. if (Subscribers != null) { Debug.Assert(Subscribers.Count > 0); // Reschedules all processes which are not completed yet. // The "where" clause filters yielders, so that only those processes // which are still running are picked up for scheduling. SimProcess subscriber; if (Subscribers.Count == 1 && (subscriber = Subscribers.First).IsAlive) { Env.ScheduleProcess(subscriber); } else { var en = Subscribers.GetEnumerator(); while (en.MoveNext()) { if ((subscriber = en.Current).IsAlive) { Env.ScheduleProcess(subscriber); } } } Subscribers = null; } }