/// <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> /// Builds a target type that based on declared type that is associated with the current type. /// </summary> /// <param name="declaredType"> Declared type. </param> private void BuildType(Type declaredType) { Type createdType = null; if (!this.createdTypes.TryGetValue(declaredType, out createdType)) { // Creates a new type createdType = (this.isGenericTypeDefinition) ? this.hostType.MakeGenericType(declaredType.GetGenericArguments()) : this.hostType; // Creates an activator for the created type IFunctionCallback <object> factoryMethod = ReflectionUtils.CreateInstance(createdType); // Creates the callbacks for the get/set accessors of the fields KeyAttribute keyAttribute; FormattableValue value; LinkedList <FormattableValue> loadedValues = new LinkedList <FormattableValue>(); IFunctionCallback <object, object> getAccessor = null; IActionCallback <object, object> setAccessor = null; FieldInfo[] fields = createdType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); int fieldsLength = fields.Length; FieldInfo field = null; for (int i = 0; i < fieldsLength; i++) { field = fields[i]; keyAttribute = field.GetAttribute <KeyAttribute>(true); if (keyAttribute != null) { getAccessor = ReflectionUtils.CreateGetAccessor(createdType, field); setAccessor = ReflectionUtils.CreateSetAccessor(createdType, field); value = new FormattableValue( keyAttribute.Name, keyAttribute.Optional, keyAttribute.Order, field.FieldType, getAccessor, setAccessor ); loadedValues.AddLast(value); } } // Action that used for getting the key attribute and property info of the overridden properties PropertyInfo property = null; MethodInfo propertyGetMethod = null; Type baseType = null; Action <Type, string> getPropertyKeyAttributeFromBase = null; getPropertyKeyAttributeFromBase = (t, n) => { baseType = t.BaseType; if (baseType == null) { return; } property = baseType.GetProperty(n, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); if (property != null) { keyAttribute = property.GetAttribute <KeyAttribute>(true); if (keyAttribute == null) { propertyGetMethod = property.GetGetMethod(true); if (propertyGetMethod == null || propertyGetMethod.GetBaseDefinition() != propertyGetMethod) { // Property is overridden - tests the properties of the base type getPropertyKeyAttributeFromBase(baseType, n); } } } else { // Required property isn't exists in the type - tests the properties of the base type getPropertyKeyAttributeFromBase(baseType, n); } }; // Creates the callbacks for the get/set accessors of the properties PropertyInfo[] properties = createdType.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); int propertiesLength = properties.Length; for (int i = 0; i < propertiesLength; i++) { property = properties[i]; keyAttribute = property.GetAttribute <KeyAttribute>(true); if (keyAttribute == null) { propertyGetMethod = property.GetGetMethod(true); if (propertyGetMethod == null || propertyGetMethod.GetBaseDefinition() != propertyGetMethod) { // Property is overridden - tests the properties of the base type getPropertyKeyAttributeFromBase(createdType, property.Name); } } if (keyAttribute == null || property.GetIndexParameters().Length != 0) { continue; } getAccessor = ReflectionUtils.CreateGetAccessor(createdType, property); setAccessor = ReflectionUtils.CreateSetAccessor(createdType, property); value = new FormattableValue( keyAttribute.Name, keyAttribute.Optional, keyAttribute.Order, property.PropertyType, getAccessor, setAccessor ); loadedValues.AddLast(value); } // Sorts the values by order FormattableValue[] sortedValues = loadedValues.ToArray(); SortUtils.QuickSort(true, sortedValues); // Saves the factory method, sorted values and created type this.factoryMethods.Add(declaredType, factoryMethod); this.values.Add(declaredType, sortedValues); this.createdTypes.Add(declaredType, createdType); } }