/// <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" ); } } }
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; }
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)); }