private List <Element> RecursiveGatherSubElements(object obj) { var elements = new List <Element>(); if (obj == null) { return(elements); } var e = obj as Element; if (e != null && Elements.ContainsKey(e.Id)) { // Do nothing. The Element has already // been added. This assumes that that the sub-elements // have been added as well and we don't need to continue. return(elements); } var t = obj.GetType(); // Ignore value types and strings // as they won't have properties that // could be elements. if (!t.IsClass || t == typeof(string)) { return(elements); } var props = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); var constrainedProps = props.Where(p => IsValidForRecursiveAddition(p.PropertyType)); foreach (var p in constrainedProps) { try { var pValue = p.GetValue(obj, null); if (pValue == null) { continue; } var elems = pValue as IList; if (elems != null) { foreach (var item in elems) { elements.AddRange(RecursiveGatherSubElements(item)); } continue; } // Get the properties dictionaries. var dict = pValue as IDictionary; if (dict != null) { foreach (var value in dict.Values) { elements.AddRange(RecursiveGatherSubElements(value)); } continue; } elements.AddRange(RecursiveGatherSubElements(pValue)); } catch (Exception ex) { throw new Exception($"The {p.Name} property or one of its children was not valid for introspection. Check the inner exception for details.", ex); } } if (e != null) { elements.Add(e); } return(elements); }