private static IDictionary <string, object> ExtractState(object o, HashSet <object> visited) { MetaType metaType = MetaType.GetMetaType(o.GetType()); Dictionary <string, object> extractedState = new Dictionary <string, object>(); if (visited.Contains(o)) { throw new InvalidOperationException(Resource.CyclicReferenceError); } else { visited.Add(o); } foreach (MetaMember metaMember in metaType.DataMembers) { object value = metaMember.GetValue(o); if (value != null && metaMember.IsComplex && !metaMember.IsCollection) { value = ExtractState(value, visited); } extractedState[metaMember.Name] = value; } return(extractedState); }
/// <summary> /// For the specified Type and original state map, this method returns a state map containing /// only values that should be roundtripped (based on RoundtripOriginal member attribution). /// </summary> /// <param name="type">The Type the state map is for.</param> /// <param name="state">The original state map.</param> /// <returns>The state map containing only values that should be rountripped.</returns> internal static IDictionary <string, object> ExtractRoundtripState(Type type, IDictionary <string, object> state) { MetaType metaType = MetaType.GetMetaType(type); Dictionary <string, object> resultRoundtripState = new Dictionary <string, object>(); foreach (MetaMember metaMember in metaType.DataMembers) { if (!metaMember.IsRoundtripMember) { // only copy RTO state continue; } if (!metaMember.IsComplex) { // for simple members, just copy the state over directly resultRoundtripState.Add(metaMember.Name, state[metaMember.Name]); } else { // if the member is complex we need to preprocess and apply values recursively if (!metaMember.IsCollection) { IDictionary <string, object> originalState = (IDictionary <string, object>)state[metaMember.Name]; if (originalState != null) { IDictionary <string, object> roundtripState = ExtractRoundtripState(metaMember.PropertyType, originalState); resultRoundtripState.Add(metaMember.Name, roundtripState); } } else { IEnumerable originalCollection = (IEnumerable)state[metaMember.Name]; if (originalCollection != null) { Type elementType = TypeUtility.GetElementType(metaMember.PropertyType); IList newCollection = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(elementType)); // Create a copy collection and copy elements recursively. Since Entity Extract/Apply state isn't // deep through complex type collections, we have to recursively do the RTO filtering here. foreach (object element in originalCollection) { IDictionary <string, object> originalState = ObjectStateUtility.ExtractState(element); if (originalState != null) { IDictionary <string, object> roundtripState = ExtractRoundtripState(elementType, originalState); object newInstance = Activator.CreateInstance(elementType); ObjectStateUtility.ApplyState(newInstance, roundtripState); newCollection.Add(newInstance); } } resultRoundtripState.Add(metaMember.Name, newCollection); } } } } return(resultRoundtripState); }
/// <summary> /// Initializes a new instance of the <see cref="ValidationResultCollection"/> class. /// </summary> /// <param name="parent">The parent instance hosting this collection.</param> internal ValidationResultCollection(object parent) { this._results = new List <ValidationResult>(); this._hasErrors = false; this._propertiesInError = Enumerable.Empty <string>(); this._parent = parent; if (this._parent != null) { this._parentMetaType = MetaType.GetMetaType(this._parent.GetType()); } }
/// <summary> /// Applies the specified state to the specified object taking the specified LoadBehavior into account. /// </summary> /// <param name="o">The object to apply state to.</param> /// <param name="stateToApply">The state dictionary.</param> /// <param name="originalState">The original state map for the modified object.</param> /// <param name="loadBehavior">The LoadBehavior to govern property merge behavior.</param> internal static void ApplyState(object o, IDictionary <string, object> stateToApply, IDictionary <string, object> originalState, LoadBehavior loadBehavior) { if (loadBehavior == LoadBehavior.KeepCurrent) { return; } MetaType metaType = MetaType.GetMetaType(o.GetType()); bool isMerging = (o as Entity) == null ? (o as ComplexObject) != null && (o as ComplexObject).IsMergingState : (o as Entity).IsMergingState; foreach (MetaMember metaMember in metaType.DataMembers) { PropertyInfo propertyInfo = metaMember.Member; object newValue; if ((isMerging && metaMember.IsMergable || !isMerging) && stateToApply.TryGetValue(propertyInfo.Name, out newValue)) { if (newValue != null && metaMember.IsComplex && !metaMember.IsCollection) { object currValue = propertyInfo.GetValue(o, null); IDictionary <string, object> newValueState = (IDictionary <string, object>)newValue; if (currValue != null) { // if the current and new values are both non-null, we have to do a merge object complexTypeOriginalValues = null; if (originalState != null) { originalState.TryGetValue(propertyInfo.Name, out complexTypeOriginalValues); } ApplyState(currValue, newValueState, (IDictionary <string, object>)complexTypeOriginalValues, loadBehavior); } else { // We do this lazy to avoid rehydrating the instance if we don't have to Lazy <object> lazy = new Lazy <object>( delegate { // Rehydrate an instance from the state dictionary. object newInstance = Activator.CreateInstance(propertyInfo.PropertyType); ApplyState(newInstance, newValueState); return(newInstance); }); ApplyValue(o, lazy, propertyInfo, originalState, loadBehavior); } } else { ApplyValue(o, newValue, propertyInfo, originalState, loadBehavior); } } } // end foreach }