protected override void OnObservedInstanceChanging(INotifyPropertyChanged oldInstance, INotifyPropertyChanged newInstance)
        {
            if (oldInstance != null)
            {
                oldInstance.PropertyChanged -= InvokeCallback;
            }
            if (newInstance != null)
            {
                newInstance.PropertyChanged += InvokeCallback;
            }

            if (_isInitialized)
            {
                PerformInvokeCallback();
            }

            if (newInstance == null)
            {
                _oldValue = default(T);
            }
            else
            {
                _oldValue = (T)ObservedProperty.GetValue(newInstance);
            }
        }
        private void HandleNextPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            if (args.PropertyName != ObservedProperty.Name)
            {
                return;
            }
            var newValue = ObservedProperty.GetValue(ObservedInstance);

            if (newValue != null && !(newValue is INotifyPropertyChanged))
            {
                throw new InvalidOperationException();
            }
            NextEntry.Reattach(newValue as INotifyPropertyChanged);
        }
        protected virtual void Reattach(INotifyPropertyChanged observedInstance)
        {
            ObservedInstance = observedInstance;

            if (observedInstance == null || NextEntry == null)
            {
                return;
            }

            var nextInstance = ObservedProperty.GetValue(ObservedInstance);

            if (nextInstance != null && !(nextInstance is INotifyPropertyChanged))
            {
                throw new InvalidOperationException();
            }
            NextEntry.Reattach(nextInstance as INotifyPropertyChanged);
        }
        private void PerformInvokeCallback()
        {
            var newValue = ObservedInstance != null ? (T)ObservedProperty.GetValue(ObservedInstance) : default(T);

            if (_oldValue == null && newValue == null)
            {
                return;
            }
            if (_oldValue != null && _oldValue.Equals(newValue))
            {
                return;
            }

            Callback?.Invoke(_oldValue, newValue);

            _oldValue = newValue;
        }