/// <summary>
        /// Gets a property change tracking for a given property
        /// </summary>
        /// <param name="some">The tracked object</param>
        /// <param name="propertyName">A property selector</param>
        /// <returns>The property tracking</returns>
        public static IObjectPropertyChangeTracking GetPropertyTracking(this object some, string propertyName)
        {
            Contract.Requires(() => some != null, "Reference must not be null because the given object is required to get its change tracker and find the desired property tracking");
            Contract.Requires(() => !string.IsNullOrEmpty(propertyName), "A property name is mandatory to get a property tracking");

            ObjectChangeTracker tracker = (ObjectChangeTracker)some.GetChangeTracker();

            if (tracker.DynamicPropertyTrackings.ContainsKey(propertyName))
            {
                return(tracker.GetDynamicTrackingByProperty(propertyName));
            }
            else
            {
                Dictionary <string, DeclaredObjectPropertyChangeTracking> declaredPropertyTrackings = tracker.PropertyTrackings
                                                                                                      .ToDictionary(t => t.Key.Name, t => t.Value);

                DeclaredObjectPropertyChangeTracking declaredPropertyTracking;

                if (declaredPropertyTrackings.TryGetValue(propertyName, out declaredPropertyTracking))
                {
                    return(declaredPropertyTracking);
                }
                else
                {
                    throw new InvalidOperationException
                          (
                              $"Cannot locate a tracking for the given property name '{propertyName}'. This can be either caused because there is more than a property with the given name or actually the given property is not being tracked for changes"
                          );
                }
            }
        }
Beispiel #2
0
 public ObjectPropertyChangeTracking(IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactoryInternal trackableObjectFactory, ObjectChangeTracker tracker, object targetObject, string propertyName, object currentValue)
 {
     Configuration          = configuration;
     TrackableObjectFactory = trackableObjectFactory;
     _tracker      = tracker;
     _targetObject = targetObject;
     PropertyName  = propertyName;
     OldValue      = currentValue;
     CurrentValue  = currentValue;
 }
Beispiel #3
0
 public DeclaredObjectPropertyChangeTracking(IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactoryInternal trackableObjectFactory, ObjectChangeTracker tracker, object targetObject, PropertyInfo ownerProperty, PropertyInfo property, object currentValue)
 {
     Configuration          = configuration;
     TrackableObjectFactory = trackableObjectFactory;
     Tracker      = tracker;
     TargetObject = targetObject;
     Property     = property;
     OldValue     = currentValue;
     CurrentValue = currentValue;
 }
        /// <summary>
        /// Turns given object and all associates to untrackable objects (i.e. POCO objects).
        /// </summary>
        /// <param name="some">The whole object to untrack</param>
        /// <returns>The untracked version of given object</returns>
        internal static object ToUntypedUntracked(this object some)
        {
            if (some == null)
            {
                return(some);
            }

            IChangeTrackableObject trackable = some as IChangeTrackableObject;

            if (trackable != null)
            {
                IProxyTargetAccessor proxyTargetAccessor = (IProxyTargetAccessor)trackable;
                object target = proxyTargetAccessor.DynProxyGetTarget();

                object unwrapped = target.CloneIt(some.GetType().GetActualTypeIfTrackable());

                ObjectChangeTracker changeTracker = (ObjectChangeTracker)trackable.GetChangeTracker();

                foreach (KeyValuePair <string, ObjectPropertyChangeTracking> dynamicProperty in changeTracker.DynamicPropertyTrackings)
                {
                    object propertyValueToSet;
                    IChangeTrackableCollection trackableCollection = dynamicProperty.Value.CurrentValue as IChangeTrackableCollection;

                    if (trackableCollection != null)
                    {
                        propertyValueToSet = ((IEnumerable)trackableCollection).ToUntrackedEnumerable(trackableCollection.GetType());
                    }
                    else
                    {
                        propertyValueToSet = dynamicProperty.Value.CurrentValue.ToUntracked();
                    }

                    unwrapped.SetDynamicMember
                    (
                        dynamicProperty.Value.PropertyName,
                        propertyValueToSet
                    );
                }

                Contract.Assert(() => !(unwrapped is IProxyTargetAccessor), "To convert a tracked object to untracked one the whole tracked object must be created from a pre-existing object");

                return(unwrapped);
            }
            else
            {
                return(some);
            }
        }
 public void StartTracking(IChangeTrackableObject trackableObject, ObjectChangeTracker currentTracker = null)
 {
     Contract.Requires(trackableObject != null, "Given reference must be non-null to be able to track it");
 }
        public object Create(object some = null, Type typeToTrack = null, ObjectChangeTracker reusedTracker = null, object parentObject = null, PropertyInfo propertyToSet = null, object[] constructorArguments = null)
        {
            typeToTrack = typeToTrack ?? some.GetType();

            ITrackableType interfaceTrackableType = null;

            if ((Configuration.CanTrackType(typeToTrack) || Configuration.ImplementsBaseType(typeToTrack, out interfaceTrackableType)) && !typeToTrack.IsTrackable())
            {
                if (interfaceTrackableType != null)
                {
                    Configuration.TrackThisTypeRecursive
                    (
                        typeToTrack,
                        trackableType =>
                    {
                        if (trackableType.Type == typeToTrack)
                        {
                            trackableType.IncludeProperties(interfaceTrackableType.IncludedProperties.ToArray());
                        }
                    }
                    );
                }

                Contract.Assert(typeToTrack.IsClass && !typeToTrack.IsAbstract && !typeToTrack.IsSealed, $"The object type to track '{typeToTrack.AssemblyQualifiedName}' must be a non-abstract, non-sealed class");

                ProxyGenerationOptions options = new ProxyGenerationOptions(new SimplePropertyInterceptionHook(Configuration));
                options.AddMixinInstance(new ChangeTrackableObjectMixin(Configuration, this));
                options.AdditionalAttributes.Add(AttributeUtil.CreateBuilder(typeof(DebuggerDisplayAttribute), new[] { $"{typeToTrack.FullName}Proxy" }));

                List <IInterceptor> interceptors = new List <IInterceptor>
                {
                    new SimplePropertyInterceptor()
                };

                if (typeToTrack.IsDynamicObject())
                {
                    interceptors.Add(new DynamicObjectInterceptor(Configuration, this));
                }

                object proxy;

                if (some != null)
                {
                    proxy = ProxyGenerator.CreateClassProxyWithTarget
                            (
                        classToProxy: typeToTrack,
                        additionalInterfacesToProxy: new[] { typeof(IChangeTrackableObject) },
                        target: some,
                        options: options,
                        interceptors: interceptors.ToArray()
                            );
                }
                else
                {
                    proxy = ProxyGenerator.CreateClassProxy
                            (
                        classToProxy: typeToTrack,
                        additionalInterfacesToProxy: new[] { typeof(IChangeTrackableObject) },
                        options: options,
                        constructorArguments: constructorArguments,
                        interceptors: interceptors.ToArray()
                            );
                }


                IChangeTrackableObject      trackableObject = (IChangeTrackableObject)proxy;
                ObjectChangeTrackingContext trackingContext = trackableObject.GetChangeTrackingContext();

                trackingContext.State = ChangeTrackableObjectState.Constructing;
                trackableObject.StartTracking(trackableObject, reusedTracker);
                trackingContext.State = ChangeTrackableObjectState.Ready;

                HashSet <PropertyInfo> propertiesToTrack =
                    new HashSet <PropertyInfo>(Configuration.GetTrackableType(typeToTrack).IncludedProperties);

                if (propertiesToTrack.Count() == 0)
                {
                    foreach (PropertyInfo property in typeToTrack.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                    {
                        propertiesToTrack.Add(property);
                    }
                }

                foreach (PropertyInfo property in propertiesToTrack)
                {
                    if (!property.IsIndexer() && property.CanReadAndWrite())
                    {
                        object propertyValue = property.GetValue(trackableObject);

                        if (propertyValue != null)
                        {
                            Create(propertyValue, trackableObject.GetChangeTrackingContext().ChangeTracker, proxy, property);
                        }
                        else
                        {
                            Create(property.PropertyType, trackableObject.GetChangeTrackingContext().ChangeTracker, proxy, property);
                        }
                    }
                }

                if (propertyToSet != null)
                {
                    propertyToSet.SetValue(parentObject ?? proxy, proxy);
                }

                trackableObject.AcceptChanges();

                return(proxy);
            }
            else
            {
                return(some);
            }
        }
 public TObject Create <TObject>(TObject some = null, ObjectChangeTracker reusedTracker = null, object parentObject = null, PropertyInfo propertyToSet = null, object[] constructorArguments = null)
     where TObject : class
 {
     return((TObject)Create(some, some == null ? typeof(TObject) : null, reusedTracker, parentObject, propertyToSet, constructorArguments));
 }
 public object Create(Type type, object some = null, ObjectChangeTracker reusedTracker = null, object parentObject = null, PropertyInfo propertyToSet = null, object[] constructorArguments = null)
 {
     return(Create(some, some == null ? type : null, reusedTracker, parentObject, propertyToSet, constructorArguments));
 }