/// <summary>
 /// Returns the value unchanged, but subscribes to its events if it is itself
 /// a ChangeableState. Designed to be used with read-only properties with
 /// pre-initialized values.
 /// </summary>
 /// <typeparam name="T">The type of the value.</typeparam>
 /// <param name="property">The name of the property the value will be assigned to.</param>
 /// <param name="value">The value to subscribe to, if it is a ChangeableState.</param>
 /// <returns></returns>
 protected T Subscribe <T>(string property, T value)
 {
     if (value is ChangeableState newSubstate)
     {
         PropertyChangeEventHandler newHandler = (object sender, PropertyChangeEventArgs e) =>
         {
             this.OnPropertyChanged(property + "." + e.PropertyName, e.NewValue);
         };
         _substates[property]         = new SubstateListener(newSubstate, newHandler);
         newSubstate.PropertyChanged += newHandler;
     }
     return(value);
 }
        private void OnPropertyChanged(string propertyName, object newValue)
        {
            bool lockTaken  = false;
            bool iAmEntrant = false;

            try
            {
                Monitor.Enter(_stateLock, ref lockTaken);

                if (reentrant)
                {
                    return;            // prevent re-entry from substate update => prevents infinite loops
                }
                reentrant = iAmEntrant = true;

                bool shouldUpdateSubstate = newValue is ChangeableState && ShouldUpdatePropertyAsSubstate(propertyName);
                if (_substates.ContainsKey(propertyName)) // discard old substate regardless
                {
                    SubstateListener substate = _substates[propertyName];
                    substate.State.PropertyChanged -= substate.Handler;
                    _substates.Remove(propertyName);
                }

                if (_pausedStateDirtySet != null) // paused?
                {
                    _pausedStateDirtySet[propertyName] = newValue;
                    return;
                }

                if (shouldUpdateSubstate)
                {
                    ChangeableState            newSubstate = (ChangeableState)newValue;
                    PropertyChangeEventHandler newHandler  = (object sender, PropertyChangeEventArgs e) =>
                    {
                        this.OnPropertyChanged(propertyName + "." + e.PropertyName, e.NewValue);
                    };
                    _substates[propertyName]     = new SubstateListener(newSubstate, newHandler);
                    newSubstate.PropertyChanged += newHandler;
                }
                PropertyChanged?.Invoke(this, new PropertyChangeEventArgs(propertyName, newValue));
            }
            finally
            {
                reentrant &= !iAmEntrant;
                if (lockTaken)
                {
                    Monitor.Exit(_stateLock);
                }
            }
        }