private static bool FilterElement(StringBuilder sb, object obj, object key, object val, bool pretty, bool includeType, bool showNulls, bool isArray, int depth, List <object> recursionStack, KeyValuePairToStringFilter filter = null) { bool unfiltered = true; if (filter != null) { string result = filter.Invoke(obj, key, val); unfiltered = result == null; if (!unfiltered && result.Length != 0) { sb.Append(result); return(true); } } if (unfiltered) { if (!isArray) { sb.Append(key).Append(pretty ? " : " : ":"); } sb.Append(Stringify(val, pretty, includeType, showNulls, true, depth + 1, recursionStack)); return(true); } return(false); }
/// <summary> /// stringifies an object using custom NonStandard rules /// </summary> /// <param name="obj"></param> /// <param name="pretty"></param> /// <param name="showType">include "=TypeName" if there could be ambiguity because of inheritance</param> /// <param name="depth"></param> /// <param name="rStack">used to prevent recursion stack overflows</param> /// <param name="filter">object0 is the object, object1 is the member, object2 is the value. if it returns null, print as usual. if returns "", skip print.</param> /// <param name="howToMarkStrongType">if null, use <see cref="StringifyTypeOfDictionary"/>, which is expected by <see cref="NonStandard.Data.CodeConvert.TryParse"/></param> /// <returns></returns> public static string Stringify(this object obj, bool pretty = true, bool showType = true, bool showNulls = false, bool showBoundary = true, int depth = 0, List <object> rStack = null, KeyValuePairToStringFilter filter = null, Func <Type, string> howToMarkStrongType = null) { if (obj == null) { return(showNulls ? "null" : ""); } if (filter != null) { string res = filter.Invoke(obj, null, null); if (res != null) { return(res); } } Type t = obj.GetType(); MethodInfo stringifyMethod = t.GetMethod("Stringify", Type.EmptyTypes); if (stringifyMethod != null) { return(stringifyMethod.Invoke(obj, Array.Empty <object>()) as string); } StringBuilder sb = new StringBuilder(); bool showTypeHere = showType; // no need to print type if there isn't type ambiguity if (showType) { Type b = t.BaseType; // if the parent class is a base class, there isn't any ambiguity if (b == typeof(ValueType) || b == typeof(System.Object) || b == typeof(Array) || t.GetCustomAttributes(false).FindIndex(o => o.GetType() == typeof(StringifyHideTypeAttribute)) >= 0) { showTypeHere = false; } } if (obj is string || t.IsPrimitive || t.IsEnum) { return(StringifiedSimple(sb, obj, showBoundary).ToString()); } if (rStack == null) { rStack = new List <object>(); } int recursionIndex = rStack.IndexOf(obj); if (recursionIndex >= 0) { return(sb.Append("/* recursed " + (rStack.Count - recursionIndex) + " */").ToString()); } rStack.Add(obj); Type listT = t.GetIListType(); if (t.IsArray || listT != null) { StringifiedList(sb, obj, listT, depth, howToMarkStrongType, filter, rStack, pretty, showBoundary, showType, showTypeHere, showNulls); } else { StringifiedObject(sb, t, obj, depth, howToMarkStrongType, filter, rStack, pretty, showBoundary, showType, showTypeHere, showNulls); } if (sb.Length == 0) { sb.Append(obj.ToString()); } return(sb.ToString()); }
private static void AppendStringifiedObjectReflection(StringBuilder sb, Type t, object obj, int depth, Func <Type, string> howToMarkStrongType, KeyValuePairToStringFilter filter, List <object> rStack, bool pretty, bool showType, bool showTypeHere, bool showNulls) { FieldInfo[] fi = t.GetFields(); for (int i = 0; i < fi.Length; ++i) { object val = fi[i].GetValue(obj); if (!showNulls && val == null) { continue; } if (i > 0 || showTypeHere) { sb.Append(","); } if (pretty) { sb.Append("\n" + StringExtension.Indentation(depth + 1)); } if (filter == null) { sb.Append(fi[i].Name).Append(pretty ? " : " : ":"); sb.Append(Stringify(val, pretty, showType, showNulls, true, depth + 1, rStack)); } else { FilterElement(sb, obj, fi[i].Name, val, pretty, showType, showNulls, false, depth, rStack, filter); } } }
private static void AppendStringifiedDictionary(StringBuilder sb, Type t, object obj, int depth, KeyValuePairToStringFilter filter, List <object> rStack, bool pretty, bool showType, bool showTypeHere, bool showNulls) { MethodInfo getEnum = t.GetMethod("GetEnumerator", new Type[] { }); MethodInfo getKey = null, getVal = null; object[] noparams = Array.Empty <object>(); IEnumerator e = getEnum.Invoke(obj, noparams) as IEnumerator; bool printed = false; while (e.MoveNext()) { object o = e.Current; if (getKey == null) { getKey = o.GetType().GetProperty("Key").GetGetMethod(); } if (getVal == null) { getVal = o.GetType().GetProperty("Value").GetGetMethod(); } if (printed || showTypeHere) { sb.Append(","); } if (pretty) { sb.Append("\n" + StringExtension.Indentation(depth + 1)); } object k = getKey.Invoke(o, noparams); object v = getVal.Invoke(o, noparams); if (!showNulls && v == null) { continue; } if (filter == null) { string keyToString = k.ToString(); if (k is string && (keyToString.ContainsNonAlphaCharacters() || CodeRules.Default.GetDelimiter(keyToString) != null)) { keyToString = keyToString.StringifySmall(); } sb.Append(keyToString).Append(pretty ? " : " : ":"); sb.Append(Stringify(v, pretty, showType, showNulls, showBoundary: true, depth + 1, rStack)); printed = true; } else { printed = FilterElement(sb, obj, k, v, pretty, showType, showNulls, false, depth, rStack, filter); } } }
private static void StringifiedObject(StringBuilder sb, Type t, object obj, int depth, Func <Type, string> howToMarkStrongType, KeyValuePairToStringFilter filter, List <object> rStack, bool pretty, bool showBoundary, bool showType, bool showTypeHere, bool showNulls) { KeyValuePair <Type, Type> kvp = t.GetIDictionaryType(); bool isDict = kvp.Key != null; if (showBoundary) { sb.Append("{"); } if (showTypeHere) { AppendType(sb, obj, depth, howToMarkStrongType, pretty); } if (!isDict) { AppendStringifiedObjectReflection(sb, t, obj, depth, howToMarkStrongType, filter, rStack, pretty, showType, showTypeHere, showNulls); } else { AppendStringifiedDictionary(sb, t, obj, depth, filter, rStack, pretty, showType, showTypeHere, showNulls); } if (pretty) { sb.Append("\n" + StringExtension.Indentation(depth)); } if (showBoundary) { sb.Append("}"); } }
private static void StringifiedList(StringBuilder sb, object obj, Type iListElement, int depth, Func <Type, string> howToMarkStrongType, KeyValuePairToStringFilter filter, List <object> rStack, bool pretty, bool showBoundary, bool showType, bool showTypeHere, bool showNulls) { if (showBoundary) { sb.Append("["); } if (showTypeHere) { AppendType(sb, obj, depth, howToMarkStrongType, pretty); } IList list = obj as IList; for (int i = 0; i < list.Count; ++i) { if (!showNulls && list[i] == null) { continue; } if (i > 0) { sb.Append(","); } if (pretty && !iListElement.IsPrimitive) { sb.Append("\n" + StringExtension.Indentation(depth + 1)); } if (filter == null) { sb.Append(Stringify(list[i], pretty, showType, showNulls, true, depth + 1, rStack)); } else { FilterElement(sb, obj, i, list[i], pretty, showType, showNulls, true, depth, rStack, filter); } } if (pretty) { sb.Append("\n" + StringExtension.Indentation(depth)); } if (showBoundary) { sb.Append("]"); } }