程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#對象轉Json對象的方案

C#對象轉Json對象的方案

編輯:關於C#

簡單,是因為只有一個類

輕量,是因為整個類代碼只有300行

靈活,是因為擴展方式只需 要繼承重寫某個方法即可

首先我將這個類稱之為JsonBuilder,我希望它以StringBuilder的方式 來實現Json字符串的轉換

public class JsonBuilder
{
    protected StringBuilder Buff = new StringBuilder(4096);//字符緩沖區
    public string ToJsonString(object obj)
    {
        .......
        return Buff.ToString();
    }
    .......
}

然後我為希望為每一個基礎類型單獨完成一個方法,並且方法可以被重寫

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)

為了使子類重寫時更方便,我將數字類型合 並為一個

protected virtual void AppendNumber(IConvertible number)

但仍然保 留原有方法,只是原有方法直接調用AppendNumber,就像這樣

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 

AppendArray(IEnumerable array)//數組,集合
protected virtual void AppendJson(IDictionary dict)//字典
protected virtual void AppendDataSet(DataSet dataset)//數據表集
protected virtual void AppendDataTable(DataTable table)//單表
protected virtual void AppendDataView(DataView view)//表視圖

ps:這些方法,單個實現 都不困難,限於篇幅問題,這裡就不介紹了,最後會放出完整代碼

已知類型處理完後,再添加一個對 未知類型的處理方法,這裡我用的是最基本的反射

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('}');
}

實際上有2個方法是目前為止不存在的

現在我們把他加上

/// 

<summary> 追加Key
/// </summary>
/// <param name="key"></param>
/// <param name="escape">key中是否有(引號,回車,制表符等)特殊字符,需要轉義

</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>();//循環引用對象緩存區
//泛對象
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");
    }
}

這2個方法都比較好理解,一個是用來處理Key的,這裡預留了一個參數escape,是為了 性能的一些考慮,比如反射時的屬性名稱,這個是絕對不可能出現一些特殊符號的,所以可以直接作為Json 的Key使用

另一個方法是用來作為泛對象(不是泛型對象)的入口方法,所有對象通過這個方法都可 以找到對應的處理方法

還有一個對象_LoopObject,這個對象是為了解決循環引用的問題的,比如 常用的對象Page(當然沒有人會把這個對象轉為Json,這裡只是用來做說明)中就有一個Page的屬性,指向 this,如果沒有額外的處理,解析將會進入一個循環遞歸,直到棧溢出(目前已知的幾個第三方組件對這個 情況的支持都不好,都會拋出異常,這個以後的文章會詳細說明),而我這裡做的處理是將這種無法解析循 環引用對象都返回undefined,也正好可以區別於空對象的null

完整代碼

using 

System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Text;
    
namespace blqw
{
    /// <summary> 用於將C#轉換為Json字符串
    /// </summary>
    public class JsonBuilder
    {
        private Dictionary<object, object> _LoopObject = new Dictionary<object, 

object>();//循環引用對象緩存區
        protected StringBuilder Buff = new StringBuilder(4096);//字符緩沖區
    
        public string ToJsonString(object obj)
        {
            Buff.Length = 0;
            AppendObject(obj);
            return Buff.ToString();
        }
        //泛對象
        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> 追加Key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="escape">key中是否有(引號,回車,制表符等)特殊字符,需要轉義

</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);
        }
        //基本類型轉換Json字符串寫入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);
        }
        //枚舉
        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));
        }
        //轉換數組對象
        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(']');
        }
        //轉換鍵值對對象
        protected virtual void AppendJson(IDictionary dict)
        {
            AppendJson(dict.Keys, dict.Values);
        }
        //分別有鍵值枚舉的對象
        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

查看本欄目

完整代碼中有部分代碼做了調整

調用部分

測試下json格式

靈活擴展

例如 上 面的栗子中,枚舉轉出的是他的字符串形式

如果現在我需要把所有枚舉轉為對應的數字怎麼做 呢?

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

新建一個類,然後重載AppendEnum就可以了

真是超級簡單的啦~~~

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved