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