/// <summary>
        /// We calling it, you are forcing a property being tracked.
        /// </summary>
        /// <param name="propertyName"></param>
        public void SingleTypePropertyNotifierPropertyChanged(string propertyName)
        {
            VariableInfoDescriptor.Flags |= BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.GetField;
            var propertyMember = SingleTypedPropertiesOwnerType.GetVariableMember(propertyName, VariableInfoDescriptor);

            // There is no member that can be handled, so we return.
            if (propertyMember == null)
            {
                return;
            }

            var          propertyType = propertyMember.GetVariableType();
            PropertyType typedPropertyValue;
            var          propertyValue = propertyMember.GetValue(SingleTypedPropertiesOwner);

            // We want to assign property value (object) to typed property value.
            if (propertyComparisonMode == PropertyComparisonMode.ValueType && TrackingPropertyType == propertyType ||
                propertyComparisonMode == PropertyComparisonMode.ReferenceType && TrackingPropertyType.IsAssignableFrom(propertyType))
            {
                typedPropertyValue = (PropertyType)propertyValue;
            }
            else
            {
                return; // The type of the property does not meet the requirements, so we skip the property
            }

            var isPropertNameTracked = cachedPropertyValues.ContainsKey(propertyName);

            // We want to abort if tracking property name is untracked and tracking property value is equals default/null.
            if (!isPropertNameTracked &&
                CanHandleDefaultValue &&
                PropertyValueEqualityComparer.Equals(typedPropertyValue !, TrackingPropertyDefaultValue !))
            {
                return;
            }

            void trackPropertyViaArgs(PropertyCachedEventArgs <PropertyType> args)
            {
                cachedPropertyValues.Add(propertyName, args.PropertyValue !);
                OnPropertyCacheAdded(args);
            }

            void trackProperty(PropertyType uncachedProperty)
            {
                var args = new PropertyCachedEventArgs <PropertyType>(propertyName, uncachedProperty);

                trackPropertyViaArgs(args);
            }

            void untrackProperty(PropertyType cachedProperty, bool isRetrack)
            {
                cachedPropertyValues.Remove(propertyName);

                if (isRetrack && CanSkipPropertyRemovedEventInvocationWhenRetracking)
                {
                    return;
                }

                var args = new PropertyCacheRemovedEventArgs <PropertyType>(propertyName, cachedProperty);

                OnPropertyCacheRemoved(args);
            }

            void retrackProperty(PropertyType cachedProperty, PropertyType uncachedProperty)
            {
                untrackProperty(cachedProperty, true);
                var args = new PropertyCachedEventArgs <PropertyType>(propertyName, uncachedProperty, cachedProperty);

                trackPropertyViaArgs(args);
            }

            if (!isPropertNameTracked)
            {
                var args = new PropertyCachingEventArgs <PropertyType>(propertyName, typedPropertyValue);
                OnPropertyCacheAdding(args);

                if (!args.CanTrackProperty)
                {
                    return;
                }

                // Add new subscription
                trackProperty(typedPropertyValue !);
            }
            else
            {
                var cachedProperty = cachedPropertyValues[propertyName];

                if (CanHandleDefaultValue && PropertyValueEqualityComparer.Equals(typedPropertyValue !, TrackingPropertyDefaultValue !))
                {
                    untrackProperty(cachedProperty, false);
                }
 protected void OnPropertyCacheRemoved(PropertyCacheRemovedEventArgs <PropertyType> args)
 => PropertyRemoved?.Invoke(this, args);