DragonECS/src/DebugUtils/JsonDebugger.cs

304 lines
9.7 KiB
C#
Raw Normal View History

2026-04-06 23:34:13 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace DCFApixels.DragonECS.Core.Internal
{
internal static class JsonDebugger
{
2026-04-07 23:38:10 +08:00
private readonly static List<string> _indentsChache = new List<string>();
2026-04-06 23:34:13 +08:00
internal static string ToJsonLog(object obj)
{
2026-04-08 14:50:30 +08:00
if (obj == null) { return "null"; }
2026-04-06 23:34:13 +08:00
var sb = new StringBuilder();
2026-04-07 23:38:10 +08:00
int linesCounter = 0;
var visited = new Dictionary<object, int>();
ToJsonLog(ref linesCounter, obj, sb, visited, 0, 2);
string json = sb.ToString();
return json;
}
private static string GetIndentString(int count)
{
int newSize = count + 1;
while (newSize > _indentsChache.Count)
{
_indentsChache.Add(new string(' ', _indentsChache.Count));
}
return _indentsChache[count];
}
private static void NewLine(
ref int linesCounter,
StringBuilder sb,
int indent,
int indentStep)
{
sb.AppendLine();
sb.Append(GetIndentString(indent * indentStep));
linesCounter++;
2026-04-06 23:34:13 +08:00
}
private static void ToJsonLog(
2026-04-07 23:38:10 +08:00
ref int linesCounter,
2026-04-06 23:34:13 +08:00
object value,
StringBuilder sb,
2026-04-07 23:38:10 +08:00
Dictionary<object, int> visited,
int indent,
int indentStep)
2026-04-06 23:34:13 +08:00
{
if (value == null)
{
sb.Append("null");
return;
}
Type type = value.GetType();
if (value is IEnumerable<char> rawString)
{
sb.Append('"');
string str = value as string;
if (str == null)
{
str = rawString.ToString();
}
EscapeString(str, sb);
sb.Append('"');
return;
}
if (type == typeof(float))
{
sb.Append(((float)value).ToString(System.Globalization.CultureInfo.InvariantCulture));
return;
}
if(type == typeof(double))
{
sb.Append(((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture));
return;
}
if (type == typeof(decimal))
{
sb.Append(((decimal)value).ToString(System.Globalization.CultureInfo.InvariantCulture));
return;
}
if (type == typeof(bool))
{
sb.Append((bool)value ? "true" : "false");
return;
}
if (type.IsEnum)
{
if(type.TryGetAttribute(out FlagsAttribute _))
{
sb.Append(type.FullName);
sb.Append('.');
sb.Append(value.ToString());
}
else
{
sb.Append(value.ToString());
}
return;
}
if (type == typeof(DateTime))
{
sb.Append('"');
sb.Append(((DateTime)value).ToString("yyyy-MM-ddTHH:mm:ss.fffZ", System.Globalization.CultureInfo.InvariantCulture));
sb.Append('"');
return;
}
if (type == typeof(Guid))
{
sb.Append('"');
sb.Append(value.ToString());
sb.Append('"');
return;
}
if (type.IsPrimitive)
{
sb.Append(value);
return;
}
if (value is Exception e)
{
sb.Append('"');
sb.Append(type.Name);
sb.Append(':').Append(' ');
sb.Append(e.Message);
sb.Append('"');
return;
}
2026-04-08 15:01:46 +08:00
if (value is Type t)
{
sb.Append('"');
sb.Append(t.GetMeta().TypeName);
sb.Append('"');
return;
}
2026-04-08 15:13:57 +08:00
if (type.Namespace == typeof(FieldInfo).Namespace || type.IsPointer)
2026-04-06 23:34:13 +08:00
{
sb.Append('"');
sb.Append(value.ToString());
sb.Append('"');
return;
}
2026-04-08 14:50:30 +08:00
if (value is Delegate del)
2026-04-06 23:34:13 +08:00
{
var list = del.GetInvocationList();
2026-04-08 14:50:30 +08:00
if (list.Length == 0)
2026-04-06 23:34:13 +08:00
{
sb.Append("null");
return;
}
if (list.Length == 1)
{
sb.Append('"');
sb.Append(del.Target.GetType().FullName);
sb.Append('.');
sb.Append(del.Method.Name);
sb.Append('"');
return;
}
2026-04-08 14:50:30 +08:00
ToJsonLog(ref linesCounter, list, sb, visited, indent, indentStep);
return;
2026-04-06 23:34:13 +08:00
}
2026-04-08 14:50:30 +08:00
if (type.IsValueType == false)
2026-04-06 23:34:13 +08:00
{
2026-04-07 23:38:10 +08:00
if (visited.TryGetValue(value, out var line))
{
sb.Append('#');
sb.Append(type.Name);
sb.Append('#');
sb.Append(line);
sb.Append('#');
return;
}
visited.Add(value, linesCounter);
2026-04-06 23:34:13 +08:00
}
2026-04-08 14:50:30 +08:00
// Collections
2026-04-07 23:38:10 +08:00
IEnumerable enumerable = value as IEnumerable;
if(enumerable != null)
{
try
{
enumerable.GetEnumerator();
}
catch (Exception)
{
enumerable = null;
}
}
if (enumerable != null)
2026-04-06 23:34:13 +08:00
{
sb.Append('[');
bool first = true;
foreach (object item in enumerable)
{
if (!first) { sb.Append(','); } else { first = false; }
2026-04-07 23:38:10 +08:00
NewLine(ref linesCounter, sb, indent + 1, indentStep);
ToJsonLog(ref linesCounter, item, sb, visited, indent + 1, indentStep);
2026-04-06 23:34:13 +08:00
}
2026-04-08 14:50:30 +08:00
// перенос строки если были элементы
2026-04-06 23:34:13 +08:00
if (!first)
{
2026-04-07 23:38:10 +08:00
NewLine(ref linesCounter, sb, indent, indentStep);
2026-04-06 23:34:13 +08:00
}
sb.Append(']');
}
else // Object
{
sb.Append('{');
2026-04-08 15:01:46 +08:00
{
NewLine(ref linesCounter, sb, indent + 1, indentStep);
sb.Append("\"Type\": ");
ToJsonLog(ref linesCounter, type, sb, visited, indent + 1, indentStep);
}
2026-04-06 23:34:13 +08:00
// Fields
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var field in fields)
{
2026-04-08 15:01:46 +08:00
if (field.IsStatic) { continue; }
2026-04-06 23:34:13 +08:00
2026-04-07 23:38:10 +08:00
NewLine(ref linesCounter, sb, indent + 1, indentStep);
2026-04-06 23:34:13 +08:00
sb.Append('"');
sb.Append(field.Name);
sb.Append('"');
sb.Append(':').Append(' ');
object fieldValue = field.GetValue(value);
2026-04-07 23:38:10 +08:00
ToJsonLog(ref linesCounter, fieldValue, sb, visited, indent + 1, 2);
2026-04-06 23:34:13 +08:00
}
// Properties
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var prop in properties)
{
if (prop.GetIndexParameters().Length > 0 ||
prop.GetMethod == null ||
prop.GetMethod.IsStatic)
2026-04-07 23:38:10 +08:00
{
2026-04-06 23:34:13 +08:00
continue;
2026-04-07 23:38:10 +08:00
}
2026-04-06 23:34:13 +08:00
2026-04-07 23:38:10 +08:00
NewLine(ref linesCounter, sb, indent + 1, indentStep);
2026-04-06 23:34:13 +08:00
sb.Append('"');
sb.Append(prop.Name);
sb.Append('"');
sb.Append(':').Append(' ');
object propValue;
try
{
propValue = prop.GetValue(value);
}
catch (Exception cathcedE)
{
propValue = cathcedE;
}
2026-04-07 23:38:10 +08:00
ToJsonLog(ref linesCounter, propValue, sb, visited, indent + 1, indentStep);
2026-04-06 23:34:13 +08:00
}
2026-04-08 15:01:46 +08:00
NewLine(ref linesCounter, sb, indent, indentStep);
2026-04-06 23:34:13 +08:00
sb.Append('}');
}
2026-04-07 23:38:10 +08:00
//visited.Remove(value);
2026-04-06 23:34:13 +08:00
}
private static void EscapeString(string s, StringBuilder sb)
{
foreach (char c in s)
{
switch (c)
{
case '"': sb.Append("\\\""); break;
case '\\': sb.Append("\\\\"); break;
case '\b': sb.Append("\\b"); break;
case '\f': sb.Append("\\f"); break;
case '\n': sb.Append("\\n"); break;
case '\r': sb.Append("\\r"); break;
case '\t': sb.Append("\\t"); break;
default:
if (char.IsControl(c))
{
sb.AppendFormat("\\u{0:x4}", (int)c);
}
else
{
sb.Append(c);
}
break;
}
}
}
}
}