public static string Dump(this object obj, int maxDepth = 4)
        {
            ObjectDumperWriter dumper = new ObjectDumperWriter(4);
            string             name   = $"<{obj?.GetType().FullName ?? null}>";

            DumpInner(dumper, name, obj, 0, maxDepth);
            return(dumper.ToString());
        }
 private static void DumpInner(ObjectDumperWriter dw, string name, object obj, int depth, int maxDepth)
 {
     if (depth > maxDepth)
     {
         dw.Add(1, "......"); return;
     }
     dw.Add(0, name);
     if (obj == null || obj is ValueType || obj is string)
     {
         dw.Add(1, $" = {obj ?? "null"}");
         dw.Add(3, (obj?.GetType().Name ?? "null"));
     }
     else
     {
         if (obj is IEnumerable list)
         {
             int count = 0;
             foreach (var item in list)
             {
                 count++;
             }
             if (obj.GetType().IsArray)
             {
                 dw.Add(1, $"   {obj.GetType().GetElementType().FullName}[{count}]");
             }
             else if (obj.GetType().IsGenericType)
             {
                 dw.Add(1, $"   {obj.GetType().GenericTypeArguments.JoinToString(o => o.FullName)}[{count}]");
             }
             else
             {
                 dw.Add(1, "   " + obj.GetType().FullName + "{" + count.ToString() + "}");
             }
             if (depth + 1 <= maxDepth)
             {
                 dw.Indent++;
                 foreach (var item in list)
                 {
                     if (item is DictionaryEntry entry)
                     {
                         DumpInner(dw, "- " + entry.Key.ToString(), entry.Value, depth + 1, maxDepth);
                     }
                     else
                     {
                         DumpInner(dw, "-", item, depth + 1, maxDepth);
                     }
                 }
                 dw.Indent--;
             }
         }
         else
         {
             dw.Add(3, $"{obj.GetType().FullName}");
             if (depth + 1 <= maxDepth)
             {
                 Type type = obj as Type;
                 if (type != null)
                 {
                     dw.Add(1, type.FullName);
                 }
                 dw.Indent++;
                 Dictionary <string, object> ObjectCache = new Dictionary <string, object>();
                 var members = (type == null) ? obj.GetType().GetMembers() : type.GetMembers();
                 foreach (var mem in members)
                 {
                     if (mem is PropertyInfo || mem is FieldInfo)
                     {
                         PropertyInfo prop  = mem as PropertyInfo;
                         FieldInfo    field = mem as FieldInfo;
                         if (prop != null)
                         {
                             if (prop.GetMethod.IsStatic ^ (obj is Type))
                             {
                                 continue;
                             }
                         }
                         object memberValue = null;
                         if (field != null)
                         {
                             memberValue = field.GetValue(obj);
                         }
                         try
                         {
                             if (prop != null)
                             {
                                 memberValue = prop.GetValue(obj);
                             }
                         }
                         catch (Exception ex)
                         {
                             dw.Add(0, mem.Name);
                             dw.Add(1, ex.Message);
                             dw.Add(3, (prop.GetMethod.ReturnType.FullName));
                             continue;
                         }
                         if (memberValue == null || memberValue is ValueType || memberValue is string)
                         {
                             DumpInner(dw, mem.Name, memberValue, depth + 1, maxDepth);
                         }
                         else
                         {
                             ObjectCache.Add(mem.Name, memberValue);
                         }
                     }
                 }
                 foreach (var kv in ObjectCache)
                 {
                     DumpInner(dw, kv.Key, kv.Value, depth + 1, maxDepth);
                 }
                 dw.Indent--;
             }
             else
             {
                 dw.Add(1, "   " + obj.ToString());
             }
         }
     }
 }