private static HtmlFormatter <T> CreateForSequence(bool includeInternals) { Type valueType = null; Func <T, IEnumerable> getKeys = null; Func <T, IEnumerable> getValues = instance => (IEnumerable)instance; var dictionaryGenericType = typeof(T).GetInterfaces() .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary <,>)); var dictionaryObjectType = typeof(T).GetInterfaces() .FirstOrDefault(i => i == typeof(IDictionary)); var enumerableGenericType = typeof(T).GetInterfaces() .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>)); if (dictionaryGenericType != null || dictionaryObjectType != null) { var keysProperty = typeof(T).GetProperty("Keys"); getKeys = instance => (IEnumerable)keysProperty.GetValue(instance, null); var valuesProperty = typeof(T).GetProperty("Values"); getValues = instance => (IEnumerable)valuesProperty.GetValue(instance, null); if (dictionaryGenericType != null) { valueType = typeof(T).GenericTypeArguments[1]; } } else if (enumerableGenericType != null) { if (!enumerableGenericType.IsArray) { var genericTypeArguments = typeof(T).GenericTypeArguments; if (genericTypeArguments.Length == 1) { valueType = genericTypeArguments[0]; } } } var destructurer = valueType != null ? Destructurer.Create(valueType) : null; return(new HtmlFormatter <T>((instance, writer) => { var index = 0; IHtmlContent indexHeader = null; Func <string> getIndex; if (getKeys != null) { var keys = new List <string>(); foreach (var key in getKeys(instance)) { keys.Add(key.ToString()); } getIndex = () => keys[index]; indexHeader = th(i("key")); } else { getIndex = () => index.ToString(); indexHeader = th(i("index")); } var rows = new List <IHtmlContent>(); List <IHtmlContent> headers = null; foreach (var item in getValues(instance)) { var dictionary = (destructurer ?? Destructurer.Create(item.GetType())).Destructure(item); if (headers == null) { headers = new List <IHtmlContent>(); headers.Add(indexHeader); headers.AddRange(dictionary.Keys .Select(k => (IHtmlContent)th(k))); } var cells = new IHtmlContent[] { td(getIndex().ToHtmlContent()) } .Concat( dictionary .Values .Select(v => (IHtmlContent)td(v))); rows.Add(tr(cells)); index++; } var view = HtmlFormatter.Table(headers, rows); view.WriteTo(writer, HtmlEncoder.Default); })); }
private static HtmlFormatter <T> CreateForSequence(bool includeInternals) { IDestructurer destructurer = null; if (typeof(T).IsConstructedGenericType) { var dictionaryType = typeof(T).GetInterfaces() .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary <,>)); if (dictionaryType != null) { var itemType = dictionaryType.GenericTypeArguments.ElementAt(1); destructurer = Destructurer.Create(itemType); } if (destructurer == null) { var ienumerableType = typeof(T).GetInterfaces() .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>)); if (ienumerableType != null) { var itemType = ienumerableType.GenericTypeArguments.Single(); destructurer = Destructurer.Create(itemType); } } } return(new HtmlFormatter <T>((instance, writer) => { var index = 0; IEnumerable sequence = instance switch { IDictionary d => d.Values, IEnumerable s => s, _ => throw new ArgumentException($"{instance.GetType()} is not IEnumerable") }; IHtmlContent indexHeader = null; Func <string> getIndex; switch (instance) { case IDictionary dict: var keys = new string[dict.Keys.Count]; dict.Keys.CopyTo(keys, 0); getIndex = () => keys[index]; indexHeader = th(i("key")); break; default: getIndex = () => index.ToString(); indexHeader = th(i("index")); break; } var rows = new List <IHtmlContent>(); List <IHtmlContent> headers = null; foreach (var item in sequence) { var dictionary = (destructurer ?? Destructurer.Create(item.GetType())).Destructure(item); if (headers == null) { headers = new List <IHtmlContent>(); headers.Add(indexHeader); headers.AddRange(dictionary.Keys .Select(k => (IHtmlContent)th(k))); } var cells = new IHtmlContent[] { td(getIndex().ToHtmlContent()) } .Concat( dictionary .Values .Select(v => (IHtmlContent)td(v))); rows.Add(tr(cells)); index++; } var view = HtmlFormatter.Table(headers, rows); view.WriteTo(writer, HtmlEncoder.Default); })); }