Skip to content

Instantly share code, notes, and snippets.

@mlehmk
Created October 27, 2017 16:36
Show Gist options
  • Save mlehmk/4960e0da8fa81bd816b6fe01ab1a0882 to your computer and use it in GitHub Desktop.
Save mlehmk/4960e0da8fa81bd816b6fe01ab1a0882 to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
namespace HaSeWaWiModule
{
public static class Json
{
[ThreadStatic] private static StringBuilder _sb;
private static void SerializeString(string s)
{
_sb.Append('"');
foreach (var c in s)
{
switch (c)
{
case '\b':
_sb.Append("\\b");
break;
case '\\':
_sb.Append("\\\\");
break;
case '\f':
_sb.Append("\\f");
break;
case '\r':
_sb.Append("\\r");
break;
case '\n':
_sb.Append("\\n");
break;
case '\t':
_sb.Append("\\t");
break;
case '"':
_sb.Append("\\\"");
break;
default:
if (char.IsControl(c))
{
_sb.Append($"\\u{(int)c:x4}");
}
else
{
_sb.Append(c);
}
break;
}
}
_sb.Append('"');
}
internal static string Parse(string v)
{
throw new NotImplementedException();
}
private static void SerializeValue(object v, Type t, Func<object, bool> checkref)
{
if (v == null)
{
_sb.Append("null");
}
else
{
if (v is IEnumerable e)
{
SerializeArray(e, checkref);
return;
}
var it = t;
if (it.GenericTypeArguments.Length == 1 && it.GetGenericTypeDefinition() == typeof(Nullable<>))
{
it = it.GenericTypeArguments[0];
}
if (it.IsAssignableFrom(typeof(string)))
{
SerializeString(v.ToString());
}
else if (it == typeof(int) || it == typeof(short) || it == typeof(sbyte))
{
_sb.Append((int)v);
}
else if (it == typeof(uint) || it == typeof(ushort) || it == typeof(byte))
{
_sb.Append((uint)v);
}
else if (it == typeof(bool))
{
_sb.Append((bool)v ? "true" : "false");
}
else if (it == typeof(decimal) || it == typeof(long) || it == typeof(ulong))
{
_sb.Append(((decimal)v).ToString(CultureInfo.InvariantCulture));
}
else if (it == typeof(float) || it == typeof(double))
{
_sb.Append(((double)v).ToString("g17", CultureInfo.InvariantCulture));
}
else if (it == typeof(DateTime))
{
SerializeString(((DateTime)v).ToString("O", CultureInfo.InvariantCulture));
}
else if (it == typeof(DateTimeOffset))
{
SerializeString(((DateTimeOffset)v).ToString("O", CultureInfo.InvariantCulture));
}
else
{
if (checkref(v))
{
SerializeObject(v, checkref);
}
else
{
throw new Exception("Circular references");
}
}
}
}
private static void SerializeArray(IEnumerable e, Func<object, bool> checkref)
{
_sb.Append('[');
bool Checkref(object x) => checkref(x) && !ReferenceEquals(e, x);
bool first = true;
foreach (var x in e)
{
if (first)
{
first = false;
}
else
{
_sb.Append(',');
}
SerializeValue(x, x?.GetType(), Checkref);
}
_sb.Append(']');
}
private static void SerializeObject(object o, Func<object, bool> checkref)
{
Type t = o.GetType();
bool filter = t.GetCustomAttributes(typeof(DataContractAttribute), true).Length > 0;
bool Checkref(object x) => checkref(x) && !ReferenceEquals(o, x);
bool first = true;
_sb.Append('{');
foreach (var p in t.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0)
{
if(filter && p.GetCustomAttributes(typeof(DataMemberAttribute), true).Length == 0)
{
continue;
}
var v = p.GetValue(o);
if (v != null)
{
if (first)
{
first = false;
}
else
{
_sb.Append(',');
}
SerializeString(p.Name);
_sb.Append(':');
var pt = p.PropertyType;
SerializeValue(v, pt, Checkref);
}
}
}
_sb.Append('}');
}
public static string Stringify(object o)
{
if (_sb == null) _sb = new StringBuilder();
try
{
SerializeValue(o, o?.GetType(), _ => true);
return _sb.ToString();
}
finally
{
_sb.Clear();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment