/// <summary> /// Loads configuration to given Class type /// </summary> /// <typeparam name="T">Target class</typeparam> /// <param name="config">Configuration</param> /// <returns>Class, filled with configuration values oe null</returns> public static T LoadToClass <T>(ConfigValue config) where T : class, new() { if (config == null) { return(null); } if (typeof(T).GetInterfaces().Contains(typeof(ICollection))) { return(LoadToCollectionWrap <T>(config)); } var instance = new T(); foreach (var field in typeof(T).GetFields()) { var dataSourceAttribute = field.GetCustomAttribute <ConfigDataSourceAttribute>(); var path = dataSourceAttribute?.DataPath ?? field.Name.ToLowerInvariant(); if (!config.ContainsPath(path)) { // Skipping not relevant fields continue; } if (field.FieldType.GetTypeInfo().IsPrimitive || field.FieldType.GetConstructor(Type.EmptyTypes) == null) { var configValue = config.GetByPath(path); var genericAsCustom = configValue.AsConfigList().Count == 1 ? MethodAsCustom.MakeGenericMethod(field.FieldType) : MethodAsCustomFromRaw.MakeGenericMethod(field.FieldType); var value = genericAsCustom.Invoke(configValue, null); field.SetValue(instance, value); } else { var fieldType = field.FieldType; var typeSource = field.GetCustomAttribute <ConfigDataTypeSourceAttribute>(); var typeName = config.GetByPath(typeSource?.DataPath) ?.AsString() ?.ToLowerInvariant(); if (typeName != null) { var mapping = field.GetCustomAttributes <ConfigDataTypeMappingAttribute>(); fieldType = mapping ?.FirstOrDefault(attr => attr.TypeName == typeName) ?.FieldType ?? Assembly .GetEntryAssembly() .GetTypes() .Where(t => field.FieldType.IsAssignableFrom(t)) .FirstOrDefault(t => t.Name.ToLowerInvariant() == typeName) ?? throw new TypeLoadException( $"Can not find type with name '{typeName}'" ); } var genericLoadToClass = MethodLoadToClass.MakeGenericMethod(fieldType); var innerInstance = genericLoadToClass.Invoke(null, new object[] { config.GetByPath(path) }); field.SetValue(instance, innerInstance); } } return(instance); }