/// <summary> /// Adds the item. /// </summary> /// <param name="index"> /// The index. /// </param> /// <param name="item"> /// The item. /// </param> /// <param name="sourceToTarget"> /// if set to <c>true</c> from source to target. /// </param> private void AddItem(int index, object item, bool sourceToTarget = true) { ICollectionHandler handler = sourceToTarget ? this.TargetHandler : this.SourceHandler; BindContext bindContext = sourceToTarget ? this.BindTarget : this.BindSource; var list = bindContext.Value as IList; bool handled = false; if (handler != null) { handled = handler.AddItem(index, item, bindContext.Source, bindContext.Value); } if (!handled && list != null) { IDataGenerator dataGenerator = sourceToTarget ? this.TargetDataGenerator : this.SourceDataGenerator; object parameter = sourceToTarget ? this.TargetDataParameter : this.SourceDataParameter; Func <object, object, object> generator = sourceToTarget ? this.TargetGenerator : this.SourceGenerator; if (dataGenerator != null) { list.Insert(index, dataGenerator.Generate(item, parameter)); } else if (generator != null) { list.Insert(index, generator(item, parameter)); } else { list.Insert(index, item); } } }
public void ResolveReferences(ICollectionHandler handler, IJsonDict item) { deserializerState = new DeserializerStateInfo(); deserializerState.references = new Dictionary <object, IJsonDict>(); deserializerState.pending = new Stack <IEnumerable>(handler.GetContainers(item)); deserializerState.results = new Dictionary <IJsonDict, object>(); object referenceId = item.GetValueOrDefault("ref"); if (referenceId != null) { deserializerState.references[referenceId] = item; } IEnumerable enumerable; while (deserializerState.pending.Count > 0) { enumerable = deserializerState.pending.Pop(); // Debug.Log(string.Format("Processing queued item {0}", idgen.GetId(enumerable, out dummy))); var list = enumerable as IJsonList; if (list != null) { for (int index = 0; index < list.Count; ++index) { if ((item = list[index] as IJsonDict) == null) { continue; // Not an object } if ((item = ResolveItem(item)) == null) { continue; // Replacement not needed } list[index] = item; } continue; } var dict = enumerable as IJsonDict; if (dict != null) { foreach (JsonKey kvp in dict) { if ((item = kvp.Value as IJsonDict) == null) { continue; // Not an object } if ((item = ResolveItem(item)) == null) { continue; // Replacement not needed. } dict[kvp.Key] = item; } continue; } throw new SerializationException(string.Format("Unexpected enumerable of type {0}", enumerable.GetType().FullName)); } }
protected Dictionary <object, ICollectionHandler> references = new Dictionary <object, ICollectionHandler>(); // Collections that we've encountered this pass. protected object MakeReference(ICollectionHandler referenced) { if (referenced.ObjectId == null) { referenced.ObjectId = serializerState.nextReferenceId++; } return(new JsonDict { { "type", "ref" }, { "ref", referenced.ObjectId } }); }
public object Deserialize(object input) { if (input == null) { throw new SerializationException("Encountered NULL while deserializing input."); } // Primitives. input = Structure.FromPrimitive(input); if (input is Structure) { return((Structure)input); } IJsonDict dict = input as IJsonDict; if (dict == null) { throw new SerializationException("Deserializing from a " + input.GetType().Name + " is unsupported."); } // Get the deserializer for this object. // This will fail and throw an exception(by design) on unsupported types. // "ref" is also considered an unsupported type. If we see it here, it's either the top-level element // (in which case there are no other elements it could possibly be referencing), or we somehow failed // to replace it during the reference replacement run. TypeHandler handler = registry.GetDeserializer(GetTypeIdentifier(dict)).CreateHandler(this); ICollectionHandler ich = handler as ICollectionHandler; object result; if (ich != null) { // If we have a collection handler and haven't scanned for backrefs yet, scan for them. if (deserializerState == null) { ResolveReferences(ich, dict); } // Is this something we've already resolved? If so, return that reference. result = deserializerState.results.GetValueOrDefault(dict); if (result != null) { return(result); } } result = handler.ProxyDeserialize(dict); if (ich != null) { deserializerState.results[dict] = result; } return(result); }
protected virtual DataType CreateConfigurationDataType(Type type) { if (type.IsEnum) { return(new EnumDataType(type)); } else if (type.IsPrimitive) { return(new PrimitiveDataType(type)); } else if (type == typeof(string)) { return(new StringDataType()); } else if (type == typeof(DateTime)) { return(new DateTimeDataType()); } else if (type == typeof(TimeSpan)) { return(new TimeSpanDataType()); } else if (type == typeof(FilePath)) { return(new FilePathDataType()); } else if (type == typeof(XmlElement)) { return(new XmlElementDataType()); } else if (DictionaryDataType.IsDictionaryType(type)) { return(new DictionaryDataType(type)); } else { ICollectionHandler handler = GetCollectionHandler(type); if (handler != null) { return(new CollectionDataType(type, handler)); } else { return(CreateClassDataType(type)); } } }
/// <summary> /// Removes the item. /// </summary> /// <param name="index"> /// The index. /// </param> /// <param name="item"> /// The item. /// </param> /// <param name="sourceToTarget"> /// if set to <c>true</c> from source to target. /// </param> private void RemoveItem(int index, object item, bool sourceToTarget = true) { bool handled = false; BindContext bindContext = sourceToTarget ? this.BindTarget : this.BindSource; ICollectionHandler handler = sourceToTarget ? this.TargetHandler : this.SourceHandler; var list = bindContext.Value as IList; if (handler != null) { handled = handler.RemoveItem(index, item, bindContext.Source, bindContext.Value); } if (!handled && list != null) { list.RemoveAt(index); } }
/// <summary> /// Clears the items. /// </summary> /// <param name="sourceToTarget"> /// if set to <c>true</c> from source to target. /// </param> private void ClearItems(bool sourceToTarget = true) { BindContext bindContext = sourceToTarget ? this.BindTarget : this.BindSource; ICollectionHandler handler = sourceToTarget ? this.TargetHandler : this.SourceHandler; var list = bindContext.Value as IList; bool handled = false; if (handler != null) { handled = handler.Clear(bindContext.Source, bindContext.Value); } if (!handled && list != null) { list.Clear(); } }
public object Serialize(object input) { // If Unity supported a modern C# version with, say, dynamic, we could go back to the overloaded methods approach // Instead of this giant mess of if-checks if (input is PrimitiveStructure) { return(((PrimitiveStructure)input).ToPrimitive()); } ICollectionHandler referenced = serializerState.references.GetValueOrDefault(input); if (referenced != null) { return(MakeReference(referenced)); } TypeHandler handler = registry.GetSerializer(input).CreateHandler(this); // Will throw on unsupported types. if (handler is ICollectionHandler) { // It's important that the reference is set up BEFORE we serialize the handler, otherwise a nested reference to the input may fail to notice // the existing reference since we haven't created it yet. serializerState.references[input] = (ICollectionHandler)handler; } return(handler.ProxySerialize(input)); }
internal CollectionDataType(Type type, ICollectionHandler handler) : base(type) { this.handler = handler; }
void Deserialize(SerializationContext serCtx, object obj, DataCollection itemData, DataItem ukwnDataRoot, string baseName) { Hashtable expandedCollections = null; foreach (DataNode value in itemData) { ItemProperty prop = (ItemProperty)properties [baseName + value.Name]; if (prop == null) { if (value is DataItem) { DataItem root = new DataItem(); root.Name = value.Name; root.UniqueNames = ((DataItem)value).UniqueNames; if (ukwnDataRoot != null) { ukwnDataRoot.ItemData.Add(root); } Deserialize(serCtx, obj, ((DataItem)value).ItemData, root, baseName + value.Name + "/"); // If no unknown data has been added, there is no need to keep this // in the unknown items list. if (ukwnDataRoot != null && !root.HasItemData) { ukwnDataRoot.ItemData.Remove(root); } } else if (obj is IExtendedDataItem && (value.Name != "ctype" || baseName.Length > 0)) { // store unreadable raw data to a special property so it can be // serialized back an the original format is kept // The ctype attribute don't need to be stored for the root object, since // it is generated by the serializer ukwnDataRoot.ItemData.Add(value); } continue; } if (prop.WriteOnly || !prop.CanDeserialize(serCtx, obj)) { continue; } try { if (prop.ExpandedCollection) { ICollectionHandler handler = prop.ExpandedCollectionHandler; if (expandedCollections == null) { expandedCollections = new Hashtable(); } object pos, col; if (!expandedCollections.ContainsKey(prop)) { col = handler.CreateCollection(out pos, -1); } else { pos = expandedCollections [prop]; col = prop.GetValue(obj); } handler.AddItem(ref col, ref pos, prop.Deserialize(serCtx, obj, value)); expandedCollections [prop] = pos; prop.SetValue(obj, col); } else { if (prop.HasSetter && prop.DataType.CanCreateInstance) { prop.SetValue(obj, prop.Deserialize(serCtx, obj, value)); } else if (prop.DataType.CanReuseInstance) { object pval = prop.GetValue(obj); if (pval == null) { if (prop.HasSetter) { throw new InvalidOperationException("The property '" + prop.Name + "' is null and a new instance of '" + prop.PropertyType + "' can't be created."); } else { throw new InvalidOperationException("The property '" + prop.Name + "' is null and it does not have a setter."); } } prop.Deserialize(serCtx, obj, value, pval); } else { throw new InvalidOperationException("The property does not have a setter."); } } } catch (Exception ex) { throw new InvalidOperationException("Could not set property '" + prop.Name + "' in type '" + Name + "'", ex); } } }
internal DataCollection Serialize(SerializationContext serCtx, object obj) { DataCollection itemCol = new DataCollection(); foreach (ItemProperty prop in Properties) { if (prop.ReadOnly || !prop.CanSerialize(serCtx, obj)) { continue; } object val = prop.GetValue(obj); if (val == null) { continue; } if (!serCtx.IsDefaultValueSerializationForced(prop) && val.Equals(prop.DefaultValue)) { continue; } DataCollection col = itemCol; if (prop.IsNested) { col = GetNestedCollection(col, prop.NameList, 0); } if (prop.ExpandedCollection) { ICollectionHandler handler = prop.ExpandedCollectionHandler; object pos = handler.GetInitialPosition(val); while (handler.MoveNextItem(val, ref pos)) { object item = handler.GetCurrentItem(val, pos); if (item == null) { continue; } DataNode data = prop.Serialize(serCtx, obj, item); data.Name = prop.SingleName; col.Add(data); } } else { DataNode data = prop.Serialize(serCtx, obj, val); if (data == null) { continue; } col.Add(data); } } if (obj is IExtendedDataItem) { // Serialize raw data which could not be deserialized DataItem uknData = (DataItem)((IExtendedDataItem)obj).ExtendedProperties ["__raw_data"]; if (uknData != null) { itemCol.Merge(uknData.ItemData); } } return(itemCol); }
void AddProperty(object member, string name, Type memberType) { // Using inherit=false because if a base class already has an ItemProperty applied to the property // then that property will already have been added while copying props from the base class. object[] ats = Context.AttributeProvider.GetCustomAttributes(member, typeof(Attribute), false); ItemPropertyAttribute at = FindPropertyAttribute(ats, ""); if (at == null) { return; } ItemProperty prop = new ItemProperty(); prop.Name = (at.Name != null) ? at.Name : name; prop.ExpandedCollection = Context.AttributeProvider.IsDefined(member, typeof(ExpandedCollectionAttribute), true); prop.DefaultValue = at.DefaultValue; prop.IsExternal = at.IsExternal; prop.SkipEmpty = at.SkipEmpty; prop.ReadOnly = at.ReadOnly; prop.WriteOnly = at.WriteOnly; if (prop.ExpandedCollection) { ICollectionHandler handler = Context.GetCollectionHandler(memberType); if (handler == null) { throw new InvalidOperationException("ExpandedCollectionAttribute can't be applied to property '" + prop.Name + "' in type '" + ValueType + "' becuase it is not a valid collection."); } memberType = handler.GetItemType(); prop.ExpandedCollectionHandler = handler; } if (at.ValueType != null) { prop.PropertyType = at.ValueType; } else { prop.PropertyType = memberType; } if (at.SerializationDataType != null) { try { prop.DataType = (DataType)Activator.CreateInstance(at.SerializationDataType, new object[] { prop.PropertyType }); } catch (MissingMethodException ex) { throw new InvalidOperationException("Constructor not found for custom data type: " + at.SerializationDataType.Name + " (Type propertyType);", ex); } } if (member is MemberInfo) { prop.Member = (MemberInfo)member; AddProperty(prop); } else { prop.InitValue = ((ItemMember)member).InitValue; AddProperty(prop, ((ItemMember)member).InsertBefore); } prop.Initialize(ats, ""); if (prop.ExpandedCollection && prop.DataType.IsSimpleType) { throw new InvalidOperationException("ExpandedCollectionAttribute is not allowed in collections of simple types"); } }
/// <summary> /// Sets the source collection handler. /// </summary> /// <param name="handler"> /// The handler. /// </param> /// <returns> /// The <see cref="WeakCollectionBinding"/>. /// </returns> public WeakCollectionBinding SetSourceCollectionHandler(ICollectionHandler handler) { this.SourceHandler = handler; return(this); }
/// <summary> /// Sets the target collection handler. /// </summary> /// <param name="handler"> /// The handler. /// </param> /// <returns> /// The <see cref="WeakCollectionBinding"/>. /// </returns> public WeakCollectionBinding SetTargetCollectionHandler(ICollectionHandler handler) { this.TargetHandler = handler; return(this); }