internal static bool ProcessGetterStrongReference(PropertyInfoEx propEx, object parentObject, ref Object lastResult) { var prop = propEx.prop; var parentInstance = parentObject as IStateObject; string propName = GetPropertyName(propEx); //Try to recover //1. First recover pointer //2. Then get surrogate string relativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(parentInstance, propName); var stateManager = StateManager.Current; var pointer = (StateObjectPointer)stateManager.GetObject(relativeUid); if (pointer != null) { if (propEx.stateManagementAttribute == StateManagementValues.ServerOnly) { stateManager.isServerSideOnly.Add(pointer); } //Extend to support other types var cachedValue = TryToRecoverWithPointer(stateManager, propEx, parentInstance, false, false, pointer: pointer); lastResult = cachedValue; return(true); } else { //There was no pointer, then return null lastResult = null; return(true); } }
internal static bool ProcessGetterTopLevelIStateObject(PropertyInfoEx propEx, object parentObject, ref Object lastValue) { if (lastValue == null) { var prop = propEx.prop; var parentInstance = parentObject as IStateObject; if (typeof(IStateObject).IsAssignableFrom(prop.DeclaringType)) { Type returnType = prop.PropertyType; var stateManager = StateManager.Current; var attributes = returnType.GetCustomAttributes(typeof(Singleton), false); if (attributes.Length > 0) { var cachedValue = stateManager.GetObject(UniqueIDGenerator.GetSinglentonUniqueId(returnType)); lastValue = cachedValue; return(true); } else { var propName = GetPropertyName(propEx); var relativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(parentInstance, propName); var pointer = (StateObjectPointer)stateManager.GetObject(relativeUid); if (pointer != null) { var cachedValue = TryToRecoverWithPointer(stateManager, propEx, parentInstance, false, pointer: pointer); lastValue = cachedValue; return(true); } } } } return(false); }
private static IStateObject GetCurrentValue(StateManager stateManager, PropertyInfoEx propEx, IStateObject parentInstance, out string valueRelativeUid, bool isNew = false) { var propName = GetPropertyName(propEx); valueRelativeUid = UniqueIDGenerator.GetRelativeUniqueID(parentInstance, propName); //First Try: Let's get the object from the Storage. var currentValue = stateManager.GetObject(valueRelativeUid); if (currentValue == null) { var pointerRelativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(parentInstance, propName); //Second try: get the Reference if present. currentValue = stateManager.GetObject(pointerRelativeUid, isNew: isNew); } return(currentValue); }
private static void AddOrUpdateReference(PropertyInfoEx propEx, IStateObject parentInstance, object newValueObj, StateObjectPointerReference currentValue = null, bool isNew = false) { var stateManager = StateManager.Current; string propName = GetPropertyName(propEx); var relativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(parentInstance, propName); var reference = currentValue; if (reference == null) { reference = stateManager.GetObject(relativeUid, isNew: isNew) as StateObjectPointerReference; } //We need to remove the pointer; if (reference != null) { // We need to remove the Reference to the value if present and if it's not a //StateObjectPointerReferenceSuperValueBase if (!(reference is StateObjectPointerReferenceSuperValueBase)) { stateManager.ReferencesManager.RemoveReference(reference, reference.Target); } // Let's check if the existing reference is compatible with the newValue to //remove it or if the value being set is null as well. if (newValueObj == null || !reference.IsCompatibleWith(newValueObj)) { //If the Reference is not compatible then we need to remove it to get a new one. stateManager.RemoveObject(relativeUid, true); reference = null; } } //Only if the newValue is not null we need a reference, otherwise lets avoid the overhead. if (newValueObj != null && reference == null) { //Gets the reference for the property. reference = GetReference(propEx, parentInstance, newValueObj); } //No reference, no value...We don't need to do anything else. else if (newValueObj == null && reference == null) { return; } //Once we got the Reference let's update it. UpdateReferenceValue(stateManager, reference, parentInstance, newValueObj); }
internal static bool ProcessGetterSurrogate(PropertyInfoEx propEx, object parentObject, ref Object lastResult) { if (lastResult == null) { var prop = propEx.prop; var parentInstance = parentObject as IStateObject; Type returnType = prop.PropertyType; string propName = GetPropertyName(propEx); //Try to recover //1. First recover pointer //2. Then get surrogate string relativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(parentInstance, propName); var stateManager = StateManager.Current; var pointer = (StateObjectPointer)stateManager.GetObject(relativeUid); if (pointer != null) { var cachedValue = TryToRecoverWithPointer(stateManager, propEx, parentInstance, true, pointer: pointer); lastResult = cachedValue; return(true); } } return(false); }
internal static EventPromiseInfo BuildContinuationInfo(StateManager stateManager, EventPromiseInfo promise, Delegate code, IStateObject parent = null, string promiseUniqueId = null, string actionID = "") { var instance = code.Target; Type codePromiseType = instance != null?instance.GetType() : null; string internalFieldsState = null; //This variable holds the reference //to the IStateObject that is closest to the promise. //For example if we are referring to a method on a Form. The closest state object is a //ViewModel. If the object is a DisplayClass, then we try to determine //which was the closest IModel or IUserControl where this DisplayClass was used IStateObject objectContainingMethod = null; if (codePromiseType != null) { //For special classes it's required to register a surrogate to save the application state. if (TypeCacheUtils.IsSpecialClass(codePromiseType)) { PromiseUtils.RegisterSurrogateForDisplayClass(codePromiseType, code.Target); objectContainingMethod = stateManager.surrogateManager.GetSurrogateFor(code.Target, generateIfNotFound: true); } else { var stateObject = instance as IStateObject; if (stateObject != null) { objectContainingMethod = stateObject; } else { var logicView = instance as ILogicView <IViewModel>; if (logicView != null) { objectContainingMethod = logicView.ViewModel; } } } } string methodArgs = null; var parameters = code.Method.GetParameters(); if (parameters.Length > 0) { StringBuilder builder = new StringBuilder(); foreach (var parameter in parameters) { builder.Append(parameter.ParameterType.AssemblyQualifiedNameCache()); builder.Append("|"); } methodArgs = builder.ToString(); } promise.DeclaringType = code.Method.DeclaringType.AssemblyQualifiedNameCache(); //promise.SetObjectContainingMethod(objectContainingMethod); promise.TargetType = code.Target != null?code.Target.GetType().AssemblyQualifiedNameCache() : null; promise.MethodName = code.Method.Name; promise.ActionID = actionID; promise.ParentId = parent != null ? parent.UniqueID : promise.ModalUniqueId = null; promise.MethodArgs = methodArgs; promise.UniqueID = promiseUniqueId ?? (parent == null ? stateManager.UniqueIDGenerator.GetPromiseUniqueID() : stateManager.UniqueIDGenerator.GetRelativeUniqueID(parent)); promise.ContinuationFields = internalFieldsState; promise.DelegateType = TypeCacheUtils.GetDelegateTypeBasedOnMethodParameters(code.Method).AssemblyQualifiedNameCache(); stateManager.AddNewObject(promise); if (objectContainingMethod != null) { if (!StateManager.AllBranchesAttached(objectContainingMethod)) { stateManager.AdoptionInformation.RegisterPossibleOrphan(promise, objectContainingMethod); } var referenceToObjectContainingMethod = new StateObjectPointerReference(); var relativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(promise, "PO"); LazyBehaviours.AddDependent(promise, UniqueIDGenerator.REFERENCEPrefix + "PO"); StateObjectPointer.AssignUniqueIdToPointer(promise, relativeUid, referenceToObjectContainingMethod); referenceToObjectContainingMethod.Target = objectContainingMethod; stateManager.isServerSideOnly.Add(referenceToObjectContainingMethod); stateManager.AddNewObject(referenceToObjectContainingMethod); stateManager.ReferencesManager.AddReference(referenceToObjectContainingMethod, objectContainingMethod); var surrogate = objectContainingMethod as StateObjectSurrogate; if (surrogate != null) { stateManager.surrogateManager.AddSurrogateReference(surrogate, referenceToObjectContainingMethod); } promise.SetObjectContainingMethod(referenceToObjectContainingMethod); } if (parent != null && objectContainingMethod != null && parent.Equals(objectContainingMethod)) { promise.isLocalInstance = true; } else if (promiseUniqueId != null && objectContainingMethod != null) { var parentUniqueID = StateManager.GetLastPartOfUniqueID(promise); promise.isLocalInstance = string.Equals(parentUniqueID, objectContainingMethod.UniqueID); } return(promise); }
internal static void ProcessSetterWeakReference(PropertyInfoEx propEx, object parentObject, object newValueObject, bool isNew = false) { //TODO might do direct cast without as. That will be slightly faster var parentInstance = parentObject as IStateObject; var stateManager = StateManager.Current; string propName = GetPropertyName(propEx); //Implementation of StateObject Reference //In this case the setter is never really used. //it is always intercepted var relativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(parentInstance, propName); var pointer = (StateObjectPointerReference)stateManager.GetObject(relativeUid, isNew: isNew); if (newValueObject == null) { if (pointer != null) { //We need to remove the pointer; stateManager.RemoveObject(relativeUid, true); } //if newValue == null and pointer == null there is nothing to do } else //New value is not null then { //did we have a value? if (pointer == null) { AddDependent(parentInstance, UniqueIDGenerator.REFERENCEPrefix + GetPropertyName(propEx)); //If not create one if (propEx.isStateObject || propEx.isAnIList || propEx.isAnIDictionary) { pointer = new StateObjectPointerReference(); if (propEx.stateManagementAttribute == StateManagementValues.ServerOnly) { stateManager.isServerSideOnly.Add(pointer); } } else if (propEx.isNonStateObjectFixedType) { pointer = new StateObjectPointerReferenceSuperValue(); } else { var stackTrace = new StackTrace(3, true); throw new InvalidOperationException( "LazyBehaviour::ProcessSetter Property with reference attribute receive a value of unsupported type.\r\n" + "Additional Info: \r\n" + "Value Type: " + newValueObject.GetType().FullName + "\r\n" + "Property Type: " + propName + "\r\n" + "Error Location: " + stackTrace); } //Surrogates are handled above StateObjectPointer.AssignUniqueIdToPointer(parentInstance, relativeUid, pointer); } var pointerReferenceSuperValue = pointer as StateObjectPointerReferenceSuperValue; var tracker = stateManager.Tracker; if (pointerReferenceSuperValue != null) { pointerReferenceSuperValue.SuperTarget = newValueObject; tracker.MarkAsModified(pointerReferenceSuperValue, "Target"); } else { var newValue = newValueObject as IStateObject; //Once we have a pointer make the newValue its new target pointer.Target = newValue; tracker.MarkAsModified(pointer, "Target"); // Here we will try to manage posible orphans assigned to Pointers if (!StateManager.AllBranchesAttached(newValue)) { stateManager.AdoptionInformation.RegisterPossibleOrphan(parentInstance, newValue, godparent: pointer); } } } }
/// <summary> /// Gets a Reference for an specified value and property. /// </summary> /// <param name="propEx">The property associated to the value being set.</param> /// <param name="parentInstance">The parent instance of the property</param> /// <param name="newValueObject">The new value for the property.</param> /// <returns></returns> private static StateObjectPointerReference GetReference(PropertyInfoEx propEx, IStateObject parentInstance, object newValueObject) { StateObjectPointerReference reference = null; string name = GetPropertyName(propEx); var relativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(parentInstance, name); AddDependent(parentInstance, UniqueIDGenerator.REFERENCEPrefix + name); //Let's try to cast the element to IStateObject var newValue = newValueObject as IStateObject; //It's an IList, IDisctionary or an IStateObject or the Value is an IStateObject if (propEx.isStateObject || propEx.isAnIList || propEx.isAnIDictionary || newValue != null) { reference = new StateObjectPointerReference(); } //It's a value type or type. else if (propEx.isNonStateObjectFixedType) { reference = new StateObjectPointerReferenceSuperValue(); } //It's declared as an Object. else if (propEx.isObjectPropertyType) { var newValueType = newValueObject.GetType(); //If the Value is an IStateObject if (newValueType.IsValueType || newValueType == typeof(string) || newValueType == typeof(Type)) { if (TypeCacheUtils.IsAnUserStructType(propEx.prop.PropertyType)) { reference = new StateObjectPointerReferenceSuperStruct(); } else { reference = new StateObjectPointerReferenceSuperValue(); } } //It's a registered surrogated. else if (SurrogatesDirectory.IsSurrogateRegistered(newValueType)) { reference = new StateObjectPointerReferenceSuperSurrogate(); } else { reference = new StateObjectPointerReferenceSerializable(); } } else //Not supported type { var stackTrace = new StackTrace(3, true); throw new InvalidOperationException( "LazyBehaviour::ProcessSetter Property with reference attribute receive a value of unsupported type.\r\n" + "Additional Info: \r\n" + "Value Type: " + propEx.prop.PropertyType.FullName + "\r\n" + "Property Type: " + GetPropertyName(propEx) + "\r\n" + "Error Location: " + stackTrace); } //If it has the StateManagement attribute set as ServerOnly, then let's respect that. if (propEx.stateManagementAttribute == StateManagementValues.ServerOnly) { StateManager.Current.isServerSideOnly.Add(reference); } //Let's set the UniqueID to the new reference. StateObjectPointer.AssignUniqueIdToPointer(parentInstance, relativeUid, reference); //Let's return the pointer of the desired type. return(reference); }
internal static void ProcessSetterSurrogate(PropertyInfoEx propEx, object parentObject, object newValueObject, bool isNew = false) { //TODO might do direct cast without as. That will be slightly faster var parentInstance = parentObject as IStateObject; var stateManager = StateManager.Current; var uuidgen = stateManager.UniqueIDGenerator; string propName = GetPropertyName(propEx); var relativeUid = UniqueIDGenerator.GetPointerRelativeUniqueID(parentInstance, propName); var pointer = (StateObjectPointer)stateManager.GetObject(relativeUid, isNew: isNew); if (newValueObject == null) { //Here we need to remove the surrogate reference if available if (propEx.hasReferenceAttribute) { //However we do no have yet implemented support for Surrogates along with references throw new NotSupportedException(); //TODO } //If there was a value there was a pointer //Surrogates are always accessed thu a pointer if (pointer != null) { //Retrieve surrogate var surrogate = (StateObjectSurrogate)pointer.Target; //Decrease surrogate references //If references drops to 0. Then remove surrogate stateManager.surrogateManager.RemoveSurrogateReference(surrogate, pointer); //Eliminate pointer stateManager.RemoveObject(pointer.UniqueID, true); } } else { bool somethingToDo = true; //Was there a previous value? If there was one then there was a pointer. //If not we need one now. if (pointer == null) { pointer = new StateObjectPointer(); AddDependent(parentInstance, UniqueIDGenerator.REFERENCEPrefix + GetPropertyName(propEx)); StateObjectPointer.AssignUniqueIdToPointer(parentInstance, relativeUid, pointer); } else { //I need to validate that the surrogate is the same and if not decrease reference //First lets see if this is same object var oldsurrogate = (StateObjectSurrogate)pointer.Target; if (oldsurrogate != null) { if (Object.ReferenceEquals(oldsurrogate.Value, newValueObject)) { //Nothing to do somethingToDo = false; } else { //Retrieve surrogate StateObjectSurrogate surrogate = stateManager.surrogateManager.GetSurrogateFor(newValueObject, generateIfNotFound: true); if (surrogate == null) { throw new Exception("Object must be instantiated/registered with resolve"); } //Add reference if needed stateManager.surrogateManager.AddSurrogateReference(surrogate, pointer, false); stateManager.RebindSurrogateReference(oldsurrogate, surrogate, pointer); somethingToDo = false; } } else { throw new InvalidOperationException("Pointer is broken. It should point to an existing surrogate"); } } if (somethingToDo) { //Retrieve surrogate StateObjectSurrogate surrogate = stateManager.surrogateManager.GetSurrogateFor(newValueObject, generateIfNotFound: true); if (surrogate == null) { throw new Exception("Object must be instantiated/registered with resolve"); } //Add reference if needed stateManager.surrogateManager.AddSurrogateReference(surrogate, pointer, false); } } }