/// <summary> /// Gets a list of ConfigFields for the given type /// </summary> /// <param name="TargetObjectType">Type to get configurable fields for</param> /// <returns>List of config fields for the given type</returns> static List <ConfigField> FindConfigFieldsForType(Type TargetObjectType) { List <ConfigField> Fields; lock (TypeToConfigFields) { if (!TypeToConfigFields.TryGetValue(TargetObjectType, out Fields)) { Fields = new List <ConfigField>(); if (TargetObjectType.BaseType != null) { Fields.AddRange(FindConfigFieldsForType(TargetObjectType.BaseType)); } foreach (FieldInfo FieldInfo in TargetObjectType.GetFields(BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { IEnumerable <ConfigFileAttribute> Attributes = FieldInfo.GetCustomAttributes <ConfigFileAttribute>(); foreach (ConfigFileAttribute Attribute in Attributes) { // Copy the field ConfigField Setter = new ConfigField(); Setter.FieldInfo = FieldInfo; Setter.Attribute = Attribute; // Check if the field type implements ICollection<>. If so, we can take multiple values. foreach (Type InterfaceType in FieldInfo.FieldType.GetInterfaces()) { if (InterfaceType.IsGenericType && InterfaceType.GetGenericTypeDefinition() == typeof(ICollection <>)) { MethodInfo MethodInfo = InterfaceType.GetRuntimeMethod("Add", new Type[] { InterfaceType.GenericTypeArguments[0] }); Setter.AddElement = (Target, Value) => { MethodInfo.Invoke(Setter.FieldInfo.GetValue(Target), new object[] { Value }); }; Setter.ElementType = InterfaceType.GenericTypeArguments[0]; break; } } // Add it to the output list Fields.Add(Setter); } } TypeToConfigFields.Add(TargetObjectType, Fields); } } return(Fields); }