/// <summary> /// Read existing items in an existing Dictionary instance. /// Used with Dictionaries of specific things which may or may not be present in the file, like Table.Columns. /// </summary> /// <typeparam name="T">Type of values in Dictionary</typeparam> /// <param name="reader">ITreeReader to read from</param> /// <param name="dictionary">Dictionary containing items to read</param> /// <param name="throwOnUnknown">True to throw for property name not in Dictionary, false to quietly skip over it</param> public static void ReadDictionaryItems <T>(this ITreeReader reader, Dictionary <string, T> dictionary, bool throwOnUnknown = true) where T : ITreeSerializable { reader.Expect(TreeToken.StartObject); reader.Read(); while (reader.TokenType == TreeToken.PropertyName) { string itemName = reader.ReadAsString(); reader.Read(); if (dictionary.TryGetValue(itemName, out T item)) { item.Read(reader); reader.Read(); } else { if (throwOnUnknown) { throw new IOException($"Found unknown {typeof(T).Name} property \"{itemName}\", expected one of \"{String.Join("; ", dictionary.Keys)}\" at {reader.Position:n0} using {reader.GetType().Name}."); } else { reader.Skip(); } } } reader.Expect(TreeToken.EndObject); }
/// <summary> /// ReadObject wraps the loop to read each property in an object and call the corresponding /// setter to set it. /// </summary> /// <remarks> /// This works for classes only, as the instance can't be passed by ref. /// Structs can serialize as arrays or directly implement the loop to decode themselves. /// Setters take a reference to the instance so that the Dictionary can be static per type, /// which is critical for acceptable performance. /// </remarks> /// <typeparam name="T">Type being deserialized</typeparam> /// <param name="reader">ITreeReader being read from</param> /// <param name="instance">T instance being initialized</param> /// <param name="setters">Dictionary of setter per field name</param> /// <param name="throwOnUnknown">Throw if property name not in setters found</param> public static void ReadObject <T>(this ITreeReader reader, T instance, Dictionary <string, Setter <T> > setters, bool throwOnUnknown = true) where T : ITreeSerializable { // Ensure object state reset before Read instance.Clear(); reader.Expect(TreeToken.StartObject); reader.Read(); while (reader.TokenType == TreeToken.PropertyName) { string propertyName = reader.ReadAsString(); reader.Read(); if (setters.TryGetValue(propertyName, out Setter <T> setter)) { setter(reader, instance); reader.Read(); } else { if (throwOnUnknown) { throw new IOException($"Found unknown {typeof(T).Name} property, \"{propertyName}\", expected one of \"{String.Join("; ", setters.Keys)}\" at {reader.Position:n0} using {reader.GetType().Name}."); } else { reader.Skip(); } } } reader.Expect(TreeToken.EndObject); // EndObject must be left for caller to handle }
public static Dictionary <string, T> ReadStringDictionary <T>(this ITreeReader reader, Func <T> ctor) where T : ITreeSerializable { if (reader.TokenType == TreeToken.Null) { return(null); } Dictionary <string, T> result = new Dictionary <string, T>(); reader.Expect(TreeToken.StartObject); reader.Read(); while (reader.TokenType == TreeToken.PropertyName) { string key = reader.ReadAsString(); reader.Read(); T value = ctor(); value.Read(reader); result[key] = value; reader.Read(); } reader.Expect(TreeToken.EndObject); return(result); }
public static Guid ReadAsGuid(this ITreeReader reader) { string writtenValue = reader.ReadAsString(); return(Guid.Parse(writtenValue)); }