public SCollect(object inInstance, Type type, IReflectionProvider provider) { _instance = inInstance; bool isHashSet = type.IsHashSet(); if (isHashSet) { _addToHashSet = provider.GetDelegate(type.GetMethod("Add")); _list = null; } else { _addToHashSet = null; _list = inInstance as IList; } }
public object DeserializeInternal(SerializedObject serialized, Type declaredType, object existingInstance) { var type = declaredType; var instance = existingInstance; // Atomic or null values if (serialized is SerializedAtom) { // The current value is replaced; they're immutable instance = (serialized as SerializedAtom).Value; } else if (serialized is SerializedXml) { var it = (serialized as SerializedXml); if (IsXmlType(declaredType)) { using (var sr = new StringReader((serialized as SerializedXml).Value)) using (var xr = XmlReader.Create(sr, new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment })) { instance = _reflectionProvider.Instantiate(declaredType); var readXml = instance as IXmlSerializable; if (readXml == null) { throw new Exception("DeserializeInternal error. readXml is null"); } readXml.ReadXml(xr); } } else if (IsSerializable(declaredType)) { using (var ms = new MemoryStream(Encoding.Default.GetBytes(it.Value))) { return(serializer.Deserialize(ms)); } } } // Dictionaries else if (type.IsGenericDictionary()) { // Instantiate if necessary if (instance == null) { instance = _reflectionProvider.Instantiate(type); } var dictionary = instance as IDictionary; if (dictionary == null) { throw new Exception("DeserializeInternal error. dictionary is null"); } var genericArguments = dictionary.GetType().GetGenericArguments(); var keyDeclaredType = genericArguments[0]; var valueDeclaredType = genericArguments[1]; var serializedAggregation = serialized as SerializedAggregate; if (serializedAggregation == null) { throw new Exception("DeserializeInternal error. serializedAggregation is null"); } foreach (var key in serializedAggregation.Children.Keys) { // Dictionaries always contain atoms as keys SafeAddToDictionary(dictionary, DeserializeInternal(key as SerializedObject, keyDeclaredType, null), DeserializeInternal(serializedAggregation.Children[key], valueDeclaredType, null)); } } // Arrays, lists and sets (any collection excluding dictionaries) else if (type.IsGenericCollection()) { var isArray = type.IsArray; var isHashSet = type.IsHashSet(); var serializedCollection = serialized as SerializedCollection; if (serializedCollection == null) { throw new Exception("DeserializeInternal error. serializedCollection is null"); } var declaredItemType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0]; var genericListType = typeof(System.Collections.Generic.List <>).MakeGenericType(declaredItemType); // Instantiate if necessary if (instance == null) { if (isArray) { instance = Array.CreateInstance(declaredItemType, serializedCollection.Items.Count); } else if (type.IsAssignableFrom(genericListType)) { instance = Activator.CreateInstance(genericListType); } else { if (declaredType.HasParameterlessConstructor()) { instance = _reflectionProvider.Instantiate(declaredType) as IEnumerable; } else if (serializedCollection.Type.HasParameterlessConstructor()) { instance = _reflectionProvider.Instantiate(serializedCollection.Type) as IEnumerable; } } } MethodHandler addToHashSet = null; if (isHashSet) { addToHashSet = _reflectionProvider.GetDelegate(type.GetMethod("Add")); } var valueIndex = 0; foreach (var item in serializedCollection.Items) { var value = DeserializeInternal(item, declaredItemType, null); if (isArray) { var list = instance as IList; if (list == null) { throw new Exception("DeserializeInternal collection error. list is null"); } list[valueIndex++] = value; } else if (isHashSet) { // Potential problem if set already contains key... addToHashSet(instance, value); } else if (instance is IList) { (instance as IList).Add(value); } else { throw new NotImplementedException(); } } } // Everything else (serialized with recursive property reflection) else { var mustInstantiate = instance == null; if (serialized.Type != null && declaredType != serialized.Type) { type = serialized.Type; mustInstantiate = true; } if (mustInstantiate) { instance = _reflectionProvider.Instantiate(type); } var serializedAggregation = serialized as SerializedAggregate; if (serializedAggregation == null) { throw new Exception("DeserializeInternal collection error. serializedAggregation is null"); } foreach (var memberInfo in _reflectionProvider.GetSerializableMembers(type)) { var memberAttr = _reflectionProvider.GetSingleAttributeOrDefault <SerializationAttribute>(memberInfo); if (memberAttr.Ignore) { continue; } var memberType = memberInfo.GetMemberType(); var name = memberAttr.Name ?? memberInfo.Name; // Checking if it's a class before doing GetValue doesn't speed up the process var valueFound = serializedAggregation.Children.ContainsKey(name); if (!valueFound) { if (memberAttr.Required) { throw new InvalidOperationException(string.Format("MissingRequiredValue {0} {1}", name, type.Name)); } } else { try { var currentValue = _reflectionProvider.GetValue(memberInfo, instance); var readValue = DeserializeInternal(serializedAggregation[name], memberType, currentValue); // This dirty check is naive and doesn't provide performance benefits //if (memberType.IsClass && readValue != currentValue && (readValue == null || !readValue.Equals(currentValue))) _reflectionProvider.SetValue(memberInfo, instance, readValue); } catch { } } } } return(instance); }