public void AddDoBehavior(TState state, Action <IUnityContainer> doAction, string doName = null)
        {
            var stateObj = this[state];
            var name     = doName ?? $"{BehavioralState.DoBehaviorName} {stateObj.DoBehaviorCount + 1}";

            if (stateObj.Editable)
            {
                stateObj.AddDoBehavior(name, doAction);
            }
            else if (RuntimeContainer.IsRegistered <object>(GlobalSynchronizerKey))
            {
                var synchronizer = RuntimeContainer.TryGetInstance <object>(GlobalSynchronizerKey);
                lock (synchronizer)
                {
                    stateObj.AddDoBehaviorUnsafe(stateObj.CreateBehavior(name, doAction));
                }
            }
            else if (BehaviorScheduler != null)
            {
                BehaviorScheduler.Schedule(() => { stateObj.AddDoBehaviorUnsafe(stateObj.CreateBehavior(name, doAction)); });
            }
            else
            {
                throw new InvalidOperationException($"{Name}: State '{stateObj.Name}' must be editable in order to add a DO behavior.");
            }
        }
        /// <summary>
        /// Construct a machine.
        /// If the runtime container has a trigger scheduler, asynchronous triggering is established.
        /// If the runtime container has a behavior scheduler, asynchronous behaviors are established.
        /// If no trigger scheduler is provided, then triggering is done synchronously using the provided synchronizing object.
        /// If no external synchronizer is provided, a default is supplied.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="runtimeContainer">Keys of interest: BehaviorSchedulerKey, TriggerSchedulerKey, GlobalSynchronizerKey.
        /// Types of interest: IClock.</param>
        /// <param name="logger"></param>
        protected StateMachineBase(string name, IUnityContainer runtimeContainer, ILog logger)
        {
            Name             = name;
            Logger           = new Logger(logger);
            RuntimeContainer = runtimeContainer ?? new UnityContainer();
            RuntimeContainer.RegisterInstance(Logger);

            // If a clock hasn't been provided, then register a standard system clock.
            if (!RuntimeContainer.IsRegistered <IClock>())
            {
                RuntimeContainer.RegisterInstance <IClock>(SystemClock.Instance);
            }

            if (logger == null && RuntimeContainer.IsRegistered <ILog>())
            {
                Logger.Log = RuntimeContainer.Resolve <ILog>();
            }

            if (Logger.Log != null)
            {
                Logger.Enable = true;
            }

            try
            {
                // A synchronizer is not used when a trigger scheduler is provided because the scheduler
                // already serializes work items by way of an work queue.
                TriggerScheduler = RuntimeContainer.Resolve <IScheduler>(TriggerSchedulerKey);
                Logger.Debug($"{Name}:  was initialized with asynchronous triggers.");
            }
            catch
            {
                // When configured with synchronous triggers, this machine must have a local synchronization context.
                // If a synchronizing object hasn't been provided, then register a new one.
                if (!RuntimeContainer.IsRegistered <object>(GlobalSynchronizerKey))
                {
                    Logger.Debug($"{Name}:  was initialized for synchronous operation using a default synchronization object.");
                    RuntimeContainer.RegisterInstance(GlobalSynchronizerKey, new object());
                }
                else
                {
                    Logger.Debug($"{Name}:  was initialized for synchronous operation.");
                }
            }

            _synchronizer = RuntimeContainer.TryGetInstance <object>(GlobalSynchronizerKey);

            try
            {
                BehaviorScheduler = RuntimeContainer.Resolve <IScheduler>(BehaviorSchedulerKey);
                Logger.Debug($"{Name}:  was initialized with asynchronous behaviors.");
            }
            catch
            {
                Logger.Debug($"{Name}:  was initialized with synchronous behaviors.");
            }
        }
        internal IBehavior CreateBehavior(string name, Action <IUnityContainer> action)
        {
            IBehavior behavior;

            if (RuntimeContainer.IsRegistered <IScheduler>(StateMachineBase.BehaviorSchedulerKey))
            {
                behavior = new ScheduledBehavior(name, action, RuntimeContainer.Resolve <IScheduler>(StateMachineBase.BehaviorSchedulerKey));
            }
            else
            {
                behavior = new Behavior(name, action);
            }

            return(behavior);
        }