private TResult GetOriginalValue <TResult>(T target, Expression <Func <T, TResult> > selector) { var propertyInfo = GetPropertyInfo(selector); string propName = propertyInfo.Name; TResult originalValue = _OriginalValueDictionary.TryGetValue(propName, out object value) ? (TResult)value : selector.Compile()(target); if (originalValue is IChangeTrackableInternal trackable) { UnrollGraph unrollGraph = new UnrollGraph(); originalValue = (TResult)trackable.GetOriginal(unrollGraph); unrollGraph.FinishWireUp(); } return(originalValue); }
public void Intercept(IInvocation invocation) { if (!IsInitialized) { return; } if (invocation.Method.IsSetter() && !_InRejectChanges) { if (_ChangeTrackingStatus == ChangeStatus.Deleted) { throw new InvalidOperationException("Can not modify deleted object"); } string propertyName = invocation.Method.PropertyName(); object previousValue = _Properties[propertyName].GetValue(invocation.Proxy, null); invocation.Proceed(); object newValue = _Properties[propertyName].GetValue(invocation.Proxy, null); if (!ReferenceEquals(previousValue, newValue)) { UnsubscribeFromChildStatusChanged(propertyName, previousValue); SubscribeToChildStatusChanged(invocation.Proxy, propertyName, newValue); } bool originalValueFound = _OriginalValueDictionary.TryGetValue(propertyName, out object originalValue); if (!originalValueFound && !Equals(previousValue, newValue)) { _OriginalValueDictionary.Add(propertyName, previousValue); SetAndRaiseStatusChanged(invocation.Proxy, parents: new List <object> { invocation.Proxy }, setStatusEvenIfStatsAddedOrDeleted: false); } else if (originalValueFound && Equals(originalValue, newValue)) { _OriginalValueDictionary.Remove(propertyName); SetAndRaiseStatusChanged(invocation.Proxy, parents: new List <object> { invocation.Proxy }, setStatusEvenIfStatsAddedOrDeleted: false); } return; } else if (invocation.Method.IsGetter()) { string propertyName = invocation.Method.PropertyName(); if (propertyName == nameof(IChangeTrackable.ChangeTrackingStatus)) { invocation.ReturnValue = _ChangeTrackingStatus; } else if (propertyName == nameof(System.ComponentModel.IChangeTracking.IsChanged)) { invocation.ReturnValue = _ChangeTrackingStatus != ChangeStatus.Unchanged; } else if (propertyName == nameof(IChangeTrackable.ChangedProperties)) { invocation.ReturnValue = GetChangedProperties(); } else { invocation.Proceed(); SubscribeToChildStatusChanged(invocation.Proxy, propertyName, invocation.ReturnValue); } return; } switch (invocation.Method.Name) { case nameof(IChangeTrackable <object> .GetOriginalValue): invocation.ReturnValue = ((dynamic)this).GetOriginalValue((T)invocation.Proxy, (dynamic)invocation.Arguments[0]); break; case nameof(IChangeTrackable <object> .GetOriginal): case nameof(IChangeTrackable <object> .GetCurrent): object poco; Func <PropertyInfo, object, object> getPropertyProxy; Func <IChangeTrackableInternal, UnrollGraph, object> getPropertyPoco; if (invocation.Method.Name == nameof(IChangeTrackable <object> .GetOriginal)) { getPropertyProxy = (property, proxy) => _OriginalValueDictionary.TryGetValue(property.Name, out object value) ? value : property.GetValue(proxy, null); getPropertyPoco = (proxy, g) => proxy.GetOriginal(g); } else { getPropertyProxy = (property, proxy) => property.GetValue(proxy, null); getPropertyPoco = (proxy, g) => proxy.GetCurrent(g); } bool isRootCall = invocation.Arguments.Length == 0; if (isRootCall) { UnrollGraph unrollGraph = new UnrollGraph(); poco = GetPoco((T)invocation.Proxy, unrollGraph, getPropertyProxy, getPropertyPoco); unrollGraph.FinishWireUp(); } else { poco = GetPoco((T)invocation.Proxy, (UnrollGraph)invocation.Arguments[0], getPropertyProxy, getPropertyPoco); } invocation.ReturnValue = poco; break; case "add_StatusChanged": _StatusChanged += (EventHandler)invocation.Arguments[0]; break; case "remove_StatusChanged": _StatusChanged -= (EventHandler)invocation.Arguments[0]; break; case "Delete": invocation.ReturnValue = Delete(invocation.Proxy); break; case "UnDelete": invocation.ReturnValue = UnDelete(invocation.Proxy); break; case nameof(IRevertibleChangeTrackingInternal.AcceptChanges): AcceptChanges(invocation.Proxy, invocation.Arguments.Length == 0 ? null : (List <object>)invocation.Arguments[0]); break; case nameof(IRevertibleChangeTrackingInternal.RejectChanges): RejectChanges(invocation.Proxy, invocation.Arguments.Length == 0 ? null : (List <object>)invocation.Arguments[0]); break; case nameof(IRevertibleChangeTrackingInternal.IsChanged): invocation.ReturnValue = GetNewChangeStatus(invocation.Proxy, (List <object>)invocation.Arguments[0]) != ChangeStatus.Unchanged; break; default: invocation.Proceed(); break; } }