/// <summary> /// /// </summary> /// <param name="content">Raw configuration file content.</param> /// <param name="configuration">The configuration object, implementing IConfigurable.</param> /// <param name="customParsers">Optional array of parser allowing to parse any type the way you want.</param> public static void AssignConfiguration(string content, IConfigurable configuration, params ICustomParser[] customParsers) { Dictionary <string, string> rawConfiguration = ParseConfiguration(content); var configurableProperties = (from p in configuration.GetType().GetProperties() let attr = p.GetCustomAttributes(typeof(MatchingKeyAttribute), true) where attr.Length == 1 select new { Property = p, Attribute = attr.First() as MatchingKeyAttribute }) .ToList(); foreach (var item in rawConfiguration) { string key = item.Key.ToLowerInvariant(); var matchingProps = configurableProperties.Where(x => x.Attribute.Key == key); PropertyInfo matchingProp = null; MatchingKeyAttribute matchingAttribute = null; if (matchingProps.Any()) { try { // try to find a matching property for this key var single = matchingProps.Single(); matchingProp = single.Property; matchingAttribute = single.Attribute; configurableProperties.Remove(single); } catch (Exception ex) { throw new Exception(string.Format("The key \"{0}\" was found multiple times!", key), ex); } // parse value var appropriateParser = customParsers.FirstOrDefault(x => x.ReturnType == matchingProp.PropertyType); if (appropriateParser != null) { object parsed = appropriateParser.Parse(item.Value, matchingAttribute.CustomParameter); matchingProp.SetValue(configuration, parsed, null); } // default parsers else if (matchingProp.PropertyType == typeof(string)) { // todo: handle default values for strings matchingProp.SetValue(configuration, item.Value, null); } else if (matchingProp.PropertyType == typeof(bool)) { if (matchingAttribute.CustomParameter is bool) { matchingProp.SetValue(configuration, ParseBool(item.Value, (bool)matchingAttribute.CustomParameter), null); } else { matchingProp.SetValue(configuration, ParseBool(item.Value), null); } } else if (matchingProp.PropertyType == typeof(int)) { if (matchingAttribute.CustomParameter is int) { matchingProp.SetValue(configuration, ParseInt(item.Value, (int)matchingAttribute.CustomParameter), null); } else { matchingProp.SetValue(configuration, ParseInt(item.Value), null); } } // TODO: default parser for other simple types (int, float...) else { throw new Exception(string.Format("Could not find a parser for type \"{0}\"!", matchingProp.PropertyType)); } } else { // no matching assignable property configuration.HandleDynamicKey(item.Key, item.Value); } } // assign default value if present for remaining properties not found in configuration foreach (var remainingPropery in configurableProperties) { // todo : throw exception if no default parameter to avoid impredictable errors? // >> need to differentiate default null from provided null if (remainingPropery.Attribute.CustomParameter != null) { remainingPropery.Property.SetValue(configuration, remainingPropery.Attribute.CustomParameter, null); } } }