public IObjectChangeTrackingConfiguration TrackThisTypeRecursive(Type rootType, Action <IConfigurableTrackableType> configure = null, TypeSearchSettings searchSettings = null)
        {
            TrackableType trackableRoot = new TrackableType(this, rootType);

            ConfigureWithAttributes(trackableRoot);
            List <TrackableType> trackableTypes = null;

            searchSettings = searchSettings ?? DefaultSearchSettings;

            if (searchSettings.Filter == null)
            {
                searchSettings.Filter = t => t.GetTypeInfo().Assembly == rootType.GetTypeInfo().Assembly;
            }

            if (searchSettings.Mode == TypeSearchMode.AttributeConfigurationOnly)
            {
                Func <Type, bool> initialFilter = searchSettings.Filter;
                searchSettings.Filter = t => initialFilter(t) && t.GetTypeInfo().GetCustomAttribute <ChangeTrackableAttribute>() != null;
            }

            trackableTypes = new List <TrackableType>
                             (
                rootType.GetAllPropertyTypesRecursive(p => p.PropertyType.GetTypeInfo().IsClass&& searchSettings.Filter(p.PropertyType)).Select
                (
                    t =>
            {
                TrackableType trackableType = new TrackableType(this, t);
                ConfigureWithAttributes(trackableType);
                configure?.Invoke(trackableType);

                return(trackableType);
            }
                )
                             );

            trackableTypes.Insert(0, new TrackableType(this, rootType));

            foreach (ITrackableType trackableType in trackableTypes)
            {
                if (!trackableType.Type.GetTypeInfo().IsInterface)
                {
                    TrackableTypes.Add(trackableType);
                }
                else
                {
                    TrackableInterfaceTypes.Add(trackableType);
                }
            }

            return(this);
        }
        public IObjectChangeTrackingConfiguration TrackThisType(Type type, Action <IConfigurableTrackableType> configure = null)
        {
            TrackableType trackableType = new TrackableType(this, type);

            ConfigureWithAttributes(trackableType);
            configure?.Invoke(trackableType);

            if (!trackableType.Type.GetTypeInfo().IsInterface)
            {
                TrackableTypes.Add(trackableType);
            }
            else
            {
                TrackableInterfaceTypes.Add(trackableType);
            }

            return(this);
        }
        /// <summary>
        /// Configures which types will support change tracking.
        /// </summary>
        /// <param name="types">The types to track its changes</param>
        public void TrackTheseTypes(params ITrackableType[] types)
        {
            Contract.Requires(() => types != null && types.Length > 0 && types.All(t => t != null), "Given types cannot be null");

            lock (_syncLock)
            {
                foreach (ITrackableType type in types)
                {
                    if (!type.Type.GetTypeInfo().IsInterface)
                    {
                        Contract.Assert(() => TrackableTypes.Add(type), "Type can only be configured to be tracked once");
                    }
                    else
                    {
                        IConfigurableTrackableType trackableType = type as IConfigurableTrackableType;
                        trackableType.IncludeProperties(type.Type.GetProperties());

                        Contract.Assert(() => TrackableInterfaceTypes.Add(type), "Interface type can only be configured to be tracked once");
                    }
                }
            }
        }