/// <summary> /// Loads the assemblies. /// </summary> /// <param name="assemblies"> Array of the used assemblies. </param> private void LoadAssemblies(params Assembly[] assemblies) { Interlocked.Exchange(ref this.formatterIsLoading, 1); Assembly assembly; Type type; Type[] types; FormattableAttribute assemblyAttribute; FormattableAttribute typeAttribute; FormattableType formattableType; LinkedList <FormattableType> loadedTypes = new LinkedList <FormattableType>(); int assembliesLength = assemblies.Length; int typesLength = 0; for (int i = 0; i < assembliesLength; i++) { assembly = assemblies[i]; if (assembly == null) { continue; } assemblyAttribute = assembly.GetAttribute <FormattableAttribute>(); if (assemblyAttribute == null) { continue; } types = assembly.GetTypes(); typesLength = types.Length; for (int k = 0; k < typesLength; k++) { type = types[k]; typeAttribute = type.GetAttribute <FormattableAttribute>(false); if (typeAttribute != null) { if (type.IsInterface || type.IsAbstract) { throw new AbstractTypeException(type); } formattableType = new FormattableType(type, typeAttribute); loadedTypes.AddLast(formattableType); } } } this.formattableTypes = loadedTypes.ToArray(); Interlocked.Exchange(ref this.formatterIsLoading, 0); }
/// <summary> /// Tries read an entry of the data by the path and creates a new class/struct. /// </summary> /// <param name="type"> The type. </param> /// <param name="className"> Name of the class. </param> /// <param name="values"> Values of the class. </param> /// <param name="path"> The path. </param> /// <param name="storer"> The storer. </param> /// <param name="entries"> List of the entries of the storer. </param> /// <param name="references"> Dictionary that contains references to the objects. </param> /// <returns> Graph if graph has been created successfully, otherwise null. </returns> private object TryReadFormattable(string path, Type type, string className, IDictionary <string, string> values, IReadOnlyDataStorer storer, LinkedList <IDataStorerEntry> entries, Dictionary <string, object> references) { // Tries get the formattable type that is related (same) with the declared type FormattableType formattableType = this.formattableTypes.FindOrDefault(f => f.Name == className && f.IsRelatedType(type, false)); if (formattableType == null) { // Tries get the formattable type that is related (not same, derived) with the declared type formattableType = this.formattableTypes.FindOrDefault(f => f.IsRelatedType(type, true)); } if (formattableType == null) { // Formattable type is null -> type isn't supported -> returns null return(null); } object graph = formattableType.CreateInstance(type); references.Add(path, graph); formattableType.OnDeserializing(graph); // Restores the keys and values of the objects FormattableValue[] formattableValues = formattableType.GetValues(type); int length = formattableValues.Length; FormattableValue value = null; Type valueType = null; string valueName = ""; for (int i = 0; i < length; i++) { value = formattableValues[i]; valueType = value.Type; valueName = value.Name; if (this.IsPrimitive(valueType)) { // Value of the object is primitive - reads it from information file Func <string, object> primitiveConverter = this.GetPrimitiveConverterToObject(valueType); if (values.ContainsKey(value.Name)) { value.SetValue(graph, primitiveConverter(values[valueName])); } else { if (!value.Optional) { throw new KeyCanNotLoadedException(formattableType, valueName); } } } else { // Value of the object isn't primitive - reads it from special file try { value.SetValue(graph, this.Read( value.Type, StringUtils.Combine(path, valueName, DirectorySeparatorString), storer, entries, references )); } catch (Exception ex) { // Thrown error if value isn't optional if (!value.Optional) { throw new KeyCanNotLoadedException(formattableType, valueName, ex); } } } } formattableType.OnDeserialized(graph); // Makes the substitution (if required) object substitution = formattableType.Substitution(graph); if (substitution != graph) { references.Remove(path); references.Add(path, substitution); // Returns the substituted graph return(substitution); } else { // Returns the created graph return(graph); } }
/// <summary> /// The exception that is thrown when key can't be saved. /// </summary> /// <param name="formattableType"> Type. </param> /// <param name="keyName"> Name of key. </param> /// <param name="exception"> Exception. </param> public KeyCanNotSavedException(FormattableType formattableType, string keyName, Exception exception) : base("Key <{0}> in <{1}> can't be saved.", exception, keyName, formattableType.Name) { }
/// <summary> /// Tries write a formattable object in the storer. /// </summary> /// <param name="graph"> Object (or graph of objects with the given root). </param> /// <param name="type"> Type of the object. </param> /// <param name="path"> The path to the file. </param> /// <param name="storer"> The storer. </param> /// <param name="references"> Dictionary that contains references to the objects. </param> /// <returns> True if formattable objecthas been written (or is exist), otherwise false. </returns> private bool TryWriteFormattable(object graph, Type type, string path, IWriteOnlyDataStorer storer, IDictionary <object, string> references) { // Gets a formattable type for the specified type FormattableType formattableType = this.formattableTypes.FindOrDefault(f => f.IsRelatedType(type, true)); if (formattableType == null) { // If formattable type isn't exists -> type isn't supported -> returns false return(false); } // Tries write the object in the storer string className = formattableType.Name; if (this.TryWriteValue(storer, path, references, graph, className)) { formattableType.OnSerializing(graph); FormattableValue[] formattableValues = formattableType.GetValues(type); FormattableValue formattableValue; int length = formattableValues.Length; object value; Type valueType; IDictionary <string, string> values = new Dictionary <string, string>(length); for (int i = 0; i < length; i++) { formattableValue = formattableValues[i]; value = formattableValue.GetValue(graph); valueType = formattableValue.Type; if (this.IsPrimitive(valueType)) { // Value of the object is primitive - writes it in the information file values.Add(formattableValue.Name, this.GetPrimitiveConverterToString(valueType)(value)); } else { // Value of the object isn't primitive - writes it in new file try { // Tries write a value in the new file this.Write( value, StringUtils.Combine(path, formattableValue.Name, DirectorySeparatorString), storer, references ); } catch (Exception ex) { // Thrown error if value isn't optional if (!formattableValue.Optional) { throw new KeyCanNotSavedException(formattableType, formattableType.Name, ex); } } } } formattableType.OnSerialized(graph); this.WriteInfo(storer, path, className, values); } return(true); }
/// <summary> /// The exception that is thrown when key can't be loaded. /// </summary> /// <param name="formattableType"> Type. </param> /// <param name="keyName"> Name of key. </param> public KeyCanNotLoadedException(FormattableType formattableType, string keyName) : base("Key <{0}> in <{1}> can't be loaded.", keyName, formattableType.Name) { }