A simple, lightweight, flexible C# object to the Json object program

Recommended for you: Get network issues from WhatsUp Gold. Not end users.

Simple , because only one class

The lightweight , because the code is only 300 lines

is flexible, because of the extension is only required to inherit can override a method


Supplement: correction cannot handle nullable value type bug


First I will this class is called JsonBuilder, I want to convert it to StringBuilder to realize the Json string

public class JsonBuilder
{
    protected StringBuilder Buff = new StringBuilder(4096);//A character buffer
    public string ToJsonString(object obj)
    {
        .......
        return Buff.ToString();
    }
    .......
}

And then I hope to finish a single method for each type of foundation, and the method of can be rewritten.

protected virtual void AppendByte(Byte value)
protected virtual void AppendDecimal(Decimal value)
protected virtual void AppendInt16(Int16 value)
protected virtual void AppendInt32(Int32 value)
protected virtual void AppendInt64(Int64 value)
protected virtual void AppendSByte(SByte value)
protected virtual void AppendUInt16(UInt16 value)
protected virtual void AppendUInt32(UInt32 value)
protected virtual void AppendUInt64(UInt64 value)
protected virtual void AppendBoolean(Boolean value)
protected virtual void AppendChar(Char value)
protected virtual void AppendString(String value)
protected virtual void AppendDateTime(DateTime value)
protected virtual void AppendGuid(Guid value)
protected virtual void AppendDouble(Double value)
protected virtual void AppendSingle(Single value)
protected virtual void AppendEnum(Enum value)

In order to make the child class to override the more convenient, I will be combined into a digital type

protected virtual void AppendNumber(IConvertible number)

But still retain the original method, but the original call the AppendNumber method directly, like this

protected virtual void AppendByte(Byte value) { AppendNumber(value); }
protected virtual void AppendDecimal(Decimal value) { AppendNumber(value); }
protected virtual void AppendInt16(Int16 value) { AppendNumber(value); }
protected virtual void AppendInt32(Int32 value) { AppendNumber(value); }
protected virtual void AppendInt64(Int64 value) { AppendNumber(value); }
protected virtual void AppendSByte(SByte value) { AppendNumber(value); }
protected virtual void AppendUInt16(UInt16 value) { AppendNumber(value); }
protected virtual void AppendUInt32(UInt32 value) { AppendNumber(value); }
protected virtual void AppendUInt64(UInt64 value) { AppendNumber(value); }
protected virtual void AppendDouble(Double value) { AppendNumber(value); }
protected virtual void AppendSingle(Single value) { AppendNumber(value); }

The advantage of this is that I can choose to override flexibly in a subclass of all numeric types, or just rewrite certain types

And then, I need to complete the conversion of some known types of methods, such as arrays, collections, dictionaries, tables etc.

protected virtual void AppendArray(IEnumerable array)//Arrays, collections
protected virtual void AppendJson(IDictionary dict)//Dictionaries
protected virtual void AppendDataSet(DataSet dataset)//The data set of tables
protected virtual void AppendDataTable(DataTable table)//Single table
protected virtual void AppendDataView(DataView view)//Table views

 Ps: these methods, single implementation is not difficult, due to space limitations, here is not introduced, finally will release the complete code

Known types of processed, and then add a processing method of unknown type, I use here is to reflect the most basic

protected virtual void AppendOther(object obj)
{
    Type t = obj.GetType();
    Buff.Append('{');
    string fix = "";
    foreach (var p in t.GetProperties())
    {
        if (p.CanRead)
        {

Buff.Append(fix); AppendKey(p.Name, false); object value = p.GetValue(obj, null); AppendObject(value); fix = ","; } } Buff.Append('}'); }



There are actually 2 method is by far not exist

We add it now

/// <summary> Additional Key
/// </summary>
/// <param name="key"></param>
/// <param name="escape">There is key (quotes, carriage return, tab) special characters, need to escape</param>
protected virtual void AppendKey(string key, bool escape)
{
    if (escape)
    {
        AppendString(key);
    }
    else
    {
        Buff.Append('"');
        Buff.Append(key);
        Buff.Append('"');
    }
    Buff.Append(':');
}
private Dictionary<object, object> _LoopObject = new Dictionary<object, object>();//Circular reference object cache
//Universal object
protected void AppendObject(object obj)
{
    if (obj == null) Buff.Append("null");else if (obj is String) AppendString((String)obj);
    else if (obj is Int32) AppendInt32((Int32)obj);
    else if (obj is Boolean) AppendBoolean((Boolean)obj);
    else if (obj is DateTime) AppendDateTime((DateTime)obj);
    else if (obj is Double) AppendDouble((Double)obj);
    else if (obj is Enum) AppendEnum((Enum)obj);
    else if (obj is Decimal) AppendDecimal((Decimal)obj)  ;
    else if (obj is Char) AppendChar((Char)obj);
    else if (obj is Single) AppendSingle((Single)obj);
    else if (obj is Guid) AppendGuid((Guid)obj);
    else if (obj is Byte) AppendByte((Byte)obj);
    else if (obj is Int16) AppendInt16((Int16)obj);
    else if (obj is Int64) AppendInt64((Int64)obj);
    else if (obj is SByte) AppendSByte((SByte)obj);
    else if (obj is UInt32) AppendUInt32((UInt32)obj);
    else if (obj is UInt64) AppendUInt64((UInt64)obj);
    else if (_LoopObject.ContainsKey(obj) == false)
    {
        _LoopObject.Add(obj, null);
        if (obj is IDictionary) AppendJson((IDictionary)obj);
        else if (obj is IEnumerable) AppendArray((IEnumerable)obj);

else if (obj is DataSet) AppendDataSet((DataSet)obj);

else if (obj is DataTable) AppendDataTable((DataTable)obj);

else if (obj is DataView) AppendDataView((DataView)obj); else AppendOther(obj); _LoopObject.Remove(obj); } else { Buff.Append("undefined"); } }

 These 2 methods are relatively well understood,

One is used to process the Key, here has reserved a parameter escape, for some consideration of performance, such as reflection property name, this is absolutely impossible in some special symbols, so it can be used directly as Json Key

Another method is used as a universal object ( is not a generic object ) the entrance method, all objects can through this method can find corresponding treatment methods

There is also a _LoopObject object,The object is to solve the problem of the circular reference,Objects such as commonly used Page ( certainly no one would call this object to Json,Here just for that ) attribute in a Page,Pointing to the this,If no additional treatment,Analytic will enter a recursive loop,Until the stack overflow ( currently supports several other third party components of this situation is not good,An exception is thrown,This article will elaborate),But I do here is this cannot resolve the circular reference object returns undefined,Also it can be distinguished from space object null

 The complete code

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace blqw
{
    /// <summary> Used for converting C# to Json string
    /// </summary>
    public class JsonBuilder
    {
        private Dictionary<object, object> _LoopObject = new Dictionary<object, object>();//Circular reference object cache
        protected StringBuilder Buff = new StringBuilder(4096);//A character buffer

        public string ToJsonString(object obj)
        {
            Buff.Length = 0;
            AppendObject(obj);
            return Buff.ToString();
        }
        //Universal object
        protected void AppendObject(object obj)
        {
            if (obj == null) Buff.Append("null");
            else if (obj is String) AppendString((String)obj);
            else if (obj is Int32) AppendInt32((Int32)obj);
            else if (obj is Boolean) AppendBoolean((Boolean)obj);
            else if (obj is DateTime) AppendDateTime((DateTime)obj);
            else if (obj is Double) AppendDouble((Double)obj);
            else if (obj is Enum) AppendEnum((Enum)obj);
            else if (obj is Decimal) AppendDecimal((Decimal)obj);
            else if (obj is Char) AppendChar((Char)obj);
            else if (obj is Single) AppendSingle((Single)obj);
            else if (obj is Guid) AppendGuid((Guid)obj);
            else if (obj is Byte) AppendByte((Byte)obj);
            else if (obj is Int16) AppendInt16((Int16)obj);
            else if (obj is Int64) AppendInt64((Int64)obj);
            else if (obj is SByte) AppendSByte((SByte)obj);
            else if (obj is UInt32) AppendUInt32((UInt32)obj);
            else if (obj is UInt64) AppendUInt64((UInt64)obj);
            else if (_LoopObject.ContainsKey(obj) == false)
            {
                _LoopObject.Add(obj, null);
                if (obj is IDictionary) AppendJson((IDictionary)obj);
                else if (obj is IEnumerable) AppendArray((IEnumerable)obj);
                else if (obj is DataSet) AppendDataSet((DataSet)obj);
                else if (obj is DataTable) AppendDataTable((DataTable)obj);
                else if (obj is DataView) AppendDataView((DataView)obj);
                else AppendOther(obj);
                _LoopObject.Remove(obj);
            }
            else
            {
                Buff.Append("undefined");
            }
        }
        protected virtual void AppendOther(object obj)
        {
            Type t = obj.GetType();
            Buff.Append('{');
            string fix = "";
            foreach (var p in t.GetProperties())
            {
                if (p.CanRead)
                {
                    Buff.Append(fix);
                    AppendKey(p.Name, false);
                    object value = p.GetValue(obj, null);
                    AppendObject(value);
                    fix = ",";
                }
            }
            Buff.Append('}');
        }
        /// <summary> "
        /// </summary>
        public const char Quot = '"';
        /// <summary> :
        /// </summary>
        public const char Colon = ':';
        /// <summary> ,
        /// </summary>
        public const char Comma = ',';
        /// <summary> Additional Key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="escape">There is key (quotes, carriage return, tab) special characters, need to escape</param>
        protected virtual void AppendKey(string key, bool escape)
        {
            if (escape)
            {
                AppendString(key);
            }
            else
            {
                Buff.Append(Quot);
                Buff.Append(key);
                Buff.Append(Quot);
            }
            Buff.Append(Colon);
        }
        //The basic types of converting Json string Buff
        protected virtual void AppendByte(Byte value) { AppendNumber(value); }
        protected virtual void AppendDecimal(Decimal value) { AppendNumber(value); }
        protected virtual void AppendInt16(Int16 value) { AppendNumber(value); }
        protected virtual void AppendInt32(Int32 value) { AppendNumber(value); }
        protected virtual void AppendInt64(Int64 value) { AppendNumber(value); }
        protected virtual void AppendSByte(SByte value) { AppendNumber(value); }
        protected virtual void AppendUInt16(UInt16 value) { AppendNumber(value); }
        protected virtual void AppendUInt32(UInt32 value) { AppendNumber(value); }
        protected virtual void AppendUInt64(UInt64 value) { AppendNumber(value); }
        protected virtual void AppendDouble(Double value) { AppendNumber(value); }
        protected virtual void AppendSingle(Single value) { AppendNumber(value); }
        protected virtual void AppendBoolean(Boolean value) { Buff.Append(value ? "true" : "false"); }
        protected virtual void AppendChar(Char value)
        {
            Buff.Append(Quot);
            switch (value)
            {
                case '\\':
                case '\n':
                case '\r':
                case '\t':
                case '"':
                    Buff.Append('\\');
                    break;
            }
            Buff.Append(value);
            Buff.Append(Quot);
        }
        protected virtual void AppendString(String value)
        {
            Buff.Append(Quot);

            for (int j = 0; j <value.Length; j++)
            {
                switch (value[j])
                {
                    case '\\':
                    case '\n':
                    case '\r':
                    case '\t':
                    case '"':
                        Buff.Append('\\');
                        break;
                }
                Buff.Append(value[j]);
            }

            Buff.Append(Quot);
        }
        protected virtual void AppendDateTime(DateTime value)
        {
            Buff.Append(Quot);
            if (value.Year <1000)
            {
                if (value.Year <100)
                {
                    if (value.Year <10)
                    {
                        Buff.Append("000");
                    }
                    else
                    {
                        Buff.Append("00");
                    }
                }
                else
                {
                    Buff.Append("0");
                }
            }
            Buff.Append(value.Year)
                .Append('-');
            if (value.Month <10)
            {
                Buff.Append('0');
            }
            Buff.Append(value.Month).Append('-');

            if (value.Day <10)
            {
                Buff.Append('0');
            }
            Buff.Append(value.Day).Append(' ');

            if (value.Hour <10)
            {
                Buff.Append('0');
            }
            Buff.Append(value.Hour).Append(Colon);

            if (value.Minute <10)
            {
                Buff.Append('0');
            }
            Buff.Append(value.Minute).Append(Colon);

            if (value.Second <10)
            {
                Buff.Append('0');
            }
            Buff.Append(value.Second).Append(Quot);
        }
        protected virtual void AppendGuid(Guid value)
        {
            Buff.Append(Quot).Append(value.ToString()).Append(Quot);
        }
        //Enumeration
        protected virtual void AppendEnum(Enum value)
        {
            Buff.Append(Quot).Append(value.ToString()).Append(Quot);
        }
        protected virtual void AppendNumber(IConvertible number)
        {
            Buff.Append(number.ToString(System.Globalization.NumberFormatInfo.InvariantInfo));
        }
        //Convert an array object
        protected virtual void AppendArray(IEnumerable array)
        {
            Buff.Append('[');
            var ee = array.GetEnumerator();
            if (ee.MoveNext())
            {
                AppendObject(ee.Current);
                while (ee.MoveNext())
                {
                    Buff.Append(Comma);
                    AppendObject(ee.Current);
                }
            }
            Buff.Append(']');
        }
        //Conversion of object key
        protected virtual void AppendJson(IDictionary dict)
        {
            AppendJson(dict.Keys, dict.Values);
        }
        //Objects are key enumeration
        protected virtual void AppendJson(IEnumerable keys, IEnumerable values)
        {
            Buff.Append('{');
            var ke = keys.GetEnumerator();
            var ve = values.GetEnumerator();
            if (ke.MoveNext() && ve.MoveNext())
            {
                AppendKey(ke.Current + "", true);
                AppendObject(ve.Current);
                while (ke.MoveNext() && ve.MoveNext())
                {
                    Buff.Append(Comma);
                    AppendKey(ke.Current + "", true);
                    AppendObject(ve.Current);
                }
            }
            Buff.Append('}');
        }

        protected virtual void AppendArray(IEnumerable enumer, Converter<object, object> getVal)
        {
            Buff.Append('[');
            var ee = enumer.GetEnumerator();
            if (ee.MoveNext())
            {
                AppendObject(ee.Current);
                while (ee.MoveNext())
                {
                    Buff.Append(Comma);
                    AppendObject(getVal(ee.Current));
                }
            }
            Buff.Append(']');
        }

        protected virtual void AppendJson(IEnumerable enumer, Converter<object, string> getKey, Converter<object, object> getVal, bool escapekey)
        {
            Buff.Append('{');

            var ee = enumer.GetEnumerator();
            if (ee.MoveNext())
            {
                AppendKey(getKey(ee.Current), escapekey);
                AppendObject(getVal(ee.Current));
                while (ee.MoveNext())
                {
                    Buff.Append(Comma);
                    AppendKey(getKey(ee.Current), true);
                    AppendObject(getVal(ee.Current));
                }
            }
            Buff.Append('}');
        }


        protected virtual void AppendDataSet(DataSet dataset)
        {
            Buff.Append('{');
            var ee = dataset.Tables.GetEnumerator();
            if (ee.MoveNext())
            {
                DataTable table = (DataTable)ee.Current;
                AppendKey(table.TableName, true);
                AppendDataTable(table);
                while (ee.MoveNext())
                {
                    Buff.Append(Comma);
                    table = (DataTable)ee.Current;
                    AppendKey(table.TableName, true);
                    AppendDataTable(table);
                }
            }
            Buff.Append('}');
        }

        protected virtual void AppendDataTable(DataTable table)
        {
            Buff.Append("{\"columns\":");
            AppendArray(table.Columns, o => ((DataColumn)o).ColumnName);
            Buff.Append(",\"rows\":");
            AppendArray(table.Rows, o => ((DataRow)o).ItemArray);
            Buff.Append('}');
        }

        protected virtual void AppendDataView(DataView tableView)
        {
            Buff.Append("{\"columns\":");
            AppendArray(tableView.Table.Columns, o => ((DataColumn)o).ColumnName);
            Buff.Append(",\"rows\":");
            AppendArray(tableView, o => ((DataRowView)o).Row.ItemArray);
            Buff.Append('}');
        }
    }
}

JsonBuilder

The complete code is part of the code to do the adjustment

Call the part

The format of JSON test


Flexible extension

For example the chestnuts, enumeration turn out is his string form

If I need to get all the enumeration to the corresponding digital do now?

public class EnumValueJsonBuilder : JsonBuilder
{
    protected override void AppendEnum(Enum value)
    {
        Buff.Append(value.GetHashCode());
    }
}

 Create a new class, and override the AppendEnum on it

It is super easy.~~~

.

.

.

.

.

However, if you think this is over, you are completely mistaken.

Now has just started..... To be continued....

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Posted by William at November 13, 2013 - 8:27 PM