public ConfigType Deserialize(ConfigType instance)
        {
            Type configType = typeof(ConfigType);

            DeserializeNodeValue(rootNode, configType, EDataTypes_Extensions.GetDataType(configType), instance);
            return(instance);
        }
        internal static void ResolveForSerialization(ref Type type, ref EDataType eType, ref object instance)
        {
            SingleFieldTypeAttribute attribute = type.GetCustomAttribute <SingleFieldTypeAttribute>();

            if (attribute == null)
            {
                return;
            }
            while (true)
            {
                FieldInfo targetField = type.GetField(attribute.fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
                if (targetField == null)
                {
                    throw new InvalidDataException($"Type '{type.FullName}' has 'SingleFieldType'-Attribute, but does not contain specified field: '{attribute.fieldName}'");
                }
                type      = targetField.FieldType;
                instance  = instance == null ? null : targetField.GetValue(instance);
                attribute = type.GetCustomAttribute <SingleFieldTypeAttribute>();
                if (attribute != null)
                {
                    continue;
                }
                eType = EDataTypes_Extensions.GetDataType(type);
                break;
            }
        }
        internal IEnumerable <string> SerializeMultiValueType(SerializationInfo serializationInfo, int currentIndentation, int currentObjectDepth,
                                                              EFormatOption keyFormatOption, EFormatOption valueFormatOption)
        {
            if (serializationInfo.dataInstance == null)
            {
                return(new string[] { });
            }
            if (!serializationInfo.eDataType.IsMultiValueType())
            {
                throw new ArgumentOutOfRangeException("eDataType: " + serializationInfo.eDataType + " is not a multi-value Type!");
            }
            switch (serializationInfo.eDataType)
            {
            case EDataType.GenericList: {
                IList     list           = (IList)serializationInfo.dataInstance;
                Type      valueType      = serializationInfo.dataType.GetGenericArguments()[0];
                EDataType valueEDataType = EDataTypes_Extensions.GetDataType(valueType);
                return((
                           from object value in list
                           select new SerializationInfo(value, valueType, valueEDataType)
                           into valueSerializationInfo
                           select SerializeListValue(valueSerializationInfo, currentIndentation, currentObjectDepth, keyFormatOption, valueFormatOption)
                           ).SelectMany(sList => sList));
            }

            case EDataType.GenericDictionary: {
                IDictionary dictionary = (IDictionary)serializationInfo.dataInstance;
                Type        keyType    = serializationInfo.dataType.GetGenericArguments()[0];
                EDataType   eKeyType   = EDataTypes_Extensions.GetDataType(keyType);
                Type        valueType  = serializationInfo.dataType.GetGenericArguments()[1];
                EDataType   eValueType = EDataTypes_Extensions.GetDataType(valueType);

                if (!eKeyType.IsSingleValueType())
                {
                    throw new InvalidDataException("Key of Config Dictionary must be Single-Value Type!");
                }

                List <string> result = new List <string>();
                foreach (DictionaryEntry entry in dictionary)
                {
                    SerializationInfo keyInfo   = new SerializationInfo(entry.Key, keyType, eKeyType);
                    SerializationInfo valueInfo = new SerializationInfo(entry.Value, valueType, eValueType);
                    result.AddRange(SerializeDictionaryEntry(keyInfo, valueInfo, currentIndentation, currentObjectDepth, keyFormatOption, valueFormatOption));
                }
                return(result);
            }

            case EDataType.NonGenericClass:
                return(SerializeNonGenericClass(serializationInfo, currentIndentation, currentObjectDepth, keyFormatOption, valueFormatOption));

            case EDataType.TypeConvertibleClass:
            case EDataType.Enum:
            case EDataType.Primitive:
            case EDataType.String:
            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        private IEnumerable <string> Serialize(object data, int currentIndentation, int currentObjectDepth, EFormatOption keyFormatOption, EFormatOption valueFormatOption)
        {
            if (data == null)
            {
                return(new string[] { });
            }
            Type              dataType          = data.GetType();
            EDataType         eDataType         = EDataTypes_Extensions.GetDataType(dataType);
            SerializationInfo serializationInfo = new SerializationInfo(data, dataType, eDataType);

            return(Serialize(serializationInfo, currentIndentation, currentObjectDepth, keyFormatOption, valueFormatOption));
        }
        private object DeserializeNodeValue(TokenNode node, Type type, EDataType eType, object instanceToUse = null)
        {
            switch (eType)
            {
            case EDataType.TypeConvertibleClass:
            case EDataType.Enum:
            case EDataType.Primitive:
            case EDataType.String: {
                return(DeserializeSimpleValue(node, type));
            }

            case EDataType.GenericList: {
                IList list          = (IList)(instanceToUse ?? Activator.CreateInstance(type));
                Type  listValueType = type.GetGenericArguments()[0];
                DeserializeListValue(node, listValueType, EDataTypes_Extensions.GetDataType(listValueType), list);
                return(list);
            }

            case EDataType.GenericDictionary: {
                IDictionary dictionary       = (IDictionary)(instanceToUse ?? (IDictionary)Activator.CreateInstance(type));
                Type[]      genericArguments = type.GetGenericArguments();
                Type        dictKeyType      = genericArguments[0];
                Type        dictValueType    = genericArguments[1];
                DeserializeDictionary(node, dictKeyType, dictValueType, EDataTypes_Extensions.GetDataType(dictValueType), dictionary);
                return(dictionary);
            }

            case EDataType.NonGenericClass: {
                if (SingleFieldTypeAttribute.IsSingleFieldType(type))
                {
                    List <FieldInfo> resolveFieldChain = SingleFieldTypeAttribute.ResolveFieldChain(type);
                    return(DeserializeSingleFieldType(node, type, instanceToUse, resolveFieldChain));
                }
                if (node.listValues.Count == 0)
                {
                    return(null);
                }
                object objectInstance = instanceToUse ?? Activator.CreateInstance(type);
                DeserializeNonGenericObject(node, type, eType, objectInstance);
                return(objectInstance);
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(eType), eType, null);
            }
        }
        private object DeserializeSingleFieldType(TokenNode node, Type objectType, object instanceToUse, IReadOnlyList <FieldInfo> fieldChain)
        {
            int fieldCount = fieldChain.Count;

            if (fieldCount <= 0)
            {
                throw new InvalidDataException($"Tried to Deserialize SingleFieldType '{objectType.FullName}' but did not find any Fields!");
            }
            FieldInfo lastField         = fieldChain[fieldCount - 1];
            EDataType lastEType         = EDataTypes_Extensions.GetDataType(lastField.FieldType);
            bool      isSingleValueType = lastEType.IsSingleValueType();

            if (isSingleValueType && node.simpleValue == null ||
                !isSingleValueType && node.listValues.Count == 0)
            {
                return(null);
            }

            object lastFieldValue = DeserializeNodeValue(node, lastField.FieldType, lastEType);

            if (lastFieldValue == null)
            {
                return(null);
            }

            object resultInstance = instanceToUse ?? Activator.CreateInstance(objectType);
            object lastInstance   = resultInstance;

            for (int i = 0; i < fieldCount - 1; i++)
            {
                FieldInfo fieldInfo  = fieldChain[i];
                object    fieldValue = Activator.CreateInstance(fieldInfo.FieldType);
                fieldInfo.SetValue(lastInstance, fieldValue);
                lastInstance = fieldValue;
            }
            lastField.SetValue(lastInstance, lastFieldValue);
            return(resultInstance);
        }
        private void DeserializeNonGenericObject(TokenNode node, Type objectType, EDataType eType, object objectInstance)
        {
            //Debug.Assert(node.listValues != null);
            Dictionary <string, FieldInfo> fieldInfos = GetTypeInfo(objectType, eType);
            List <string> keysToVerify = options.verifyAllKeysSet ? fieldInfos.Keys.ToList() : null;

            foreach (TokenNode childNode in node.listValues)
            {
                if (childNode.key == null)
                {
                    throw new InvalidDataException($"Object-Entry on Line {childNode.lineNumber} has no key!");
                }
                if (!fieldInfos.ContainsKey(childNode.key))
                {
                    throw new InvalidDataException($"Object-Entry on Line {childNode.lineNumber} has invalid key: '{childNode.key}' possible keys are: ('{string.Join("', '", fieldInfos.Keys)}')");
                }
                FieldInfo fieldInfo = fieldInfos[childNode.key];
                if (childNode.listValues == null && childNode.simpleValue == null)
                {
                    throw new InvalidDataException($"Object-Entry on Line {childNode.lineNumber} with key: '{childNode.key}' does not contain any values!");
                }
                Type fieldType = fieldInfo.FieldType;
                fieldInfo.SetValue(objectInstance, DeserializeNodeValue(childNode, fieldType, EDataTypes_Extensions.GetDataType(fieldType)));
                if (options.verifyAllKeysSet)
                {
                    keysToVerify?.Remove(childNode.key);
                }
            }
            if (options.verifyAllKeysSet)
            {
                if (keysToVerify != null && keysToVerify.Count > 0)
                {
                    throw new InvalidDataException($"Object on Line {node.lineNumber} was missing keys: ('{string.Join("', '", keysToVerify)}')");
                }
            }
        }
        private IEnumerable <string> SerializeNonGenericClass(SerializationInfo serializationInfo, int currentIndentation, int currentObjectDepth,
                                                              EFormatOption keyFormatOption, EFormatOption valueFormatOption)
        {
            List <ConfigTypeInfo> typeFieldInfo;

            if (!typeCache.ContainsKey(serializationInfo.dataType))
            {
                typeFieldInfo = ConfigTypeInfo.GatherTypeInfo(serializationInfo.dataType, options).ToList();
                typeCache[serializationInfo.dataType] = typeFieldInfo;
            }
            else
            {
                typeFieldInfo = typeCache[serializationInfo.dataType];
            }

            List <string> result = new List <string>();

            foreach (IEnumerable <string> serializeResult in
                     from configInfo in typeFieldInfo
                     let fieldValue = configInfo.fieldInfo.GetValue(serializationInfo.dataInstance)
                                      let fieldType = configInfo.fieldInfo.FieldType
                                                      let info = new SerializationInfo(fieldValue, fieldType, EDataTypes_Extensions.GetDataType(fieldType))
                                                                 select configInfo.fieldSerializer.Serialize(this, configInfo.fieldInfo, info, currentIndentation, currentObjectDepth, keyFormatOption, valueFormatOption))
            {
                result.AddRange(serializeResult);
            }
            return(result);
        }