C# 一个简陋轻便的Json字符串拼接类

有的时候我们要以Json格式的形式传递参数,用模型或匿名类传给json库转的话,感觉很浪费,但是自己手动拼的话有比较麻烦,因此封装了一个拼接类,非常简陋

2024-8-14 改进版,支持了布尔、子对象和数组等类型

JsonStringBuilder

复制代码
    /// <summary>
    /// Json字符串建造者,一般用于构建简单的json字符串
    /// </summary>
    public class JsonStringBuilder {
        readonly StringBuilder sb = new StringBuilder("{"); //不能用char,因为没有char的重载
        /// <summary>
        /// 附加一个需要用双引号引起来的元素,比如key和文本val
        /// </summary> 
        void AppendTextElement(string val) {
            //sb.Append("\"" + val + "\"");
            sb.Append('"');  //这里逐个附加字符,比附加字符串性能更好
            sb.Append(val);
            sb.Append('"');
        }
        /// <summary>
        /// 附加一个值为字符串类型的键值对
        /// </summary>
        public JsonStringBuilder Append(string key, string val) {
            if (val == null) {
                AppendNull(key);
            } else {
                AppendTextElement(key);
                sb.Append(':');
                AppendTextElement(val);
                sb.Append(',');
            }
            return this;
        }
        /// <summary>
        /// 附加一个值为日期类型的键值对
        /// </summary>
        public JsonStringBuilder Append(string key, DateTime val) {
            return Append(key, val.ToString());
        }
        /// <summary>
        /// 附加一个值为布尔类型的键值对
        /// </summary>
        public JsonStringBuilder Append(string key, bool val) {
            AppendTextElement(key);
            sb.Append(':');
            sb.Append(val ? "true" : "false");
            sb.Append(',');
            return this;
        }
        /// <summary>
        /// 附加一个值为数值类型的键值对
        /// </summary>
        public JsonStringBuilder Append<T>(string key, T val) where T : struct {
            AppendTextElement(key);
            sb.Append(':');
            sb.Append(val);
            sb.Append(',');
            return this;
        }
        /// <summary>
        /// 附加一个值为引用对象的键值对,不通过委托传递val是为了操作起来更灵活,因为不是所有的数据都被封装成了对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="val">对象,用来判断对象是否为空</param>
        /// <param name="objectAppend">附加对象中的键值对操作</param>
        /// <returns></returns>
        public JsonStringBuilder Append<T>(string key, T val, Action<JsonStringBuilder> objectAppend) where T : class {
            if (val == null) {
                AppendNull(key);
            } else {
                AppendTextElement(key);
                sb.Append(':');
                sb.Append('{');
                objectAppend(this);
                AppendObjectEnd();
            }
            return this;
        }
        /// <summary>
        /// 附加子对象的结束操作,即子对象结束后,拼接一个"},"
        /// </summary> 
        void AppendObjectEnd() {
            var end = sb[sb.Length - 1];
            if (end == ',') {
                sb[sb.Length - 1] = '}';
            } else {
                sb.Append('}');
            }
            sb.Append(',');
        }
        /// <summary>
        /// 附件一个值为null的键值对
        /// </summary>
        public JsonStringBuilder AppendNull(string key) {
            AppendTextElement(key);
            sb.Append(':');
            sb.Append('n');
            sb.Append('u');
            sb.Append('l');
            sb.Append('l');
            sb.Append(',');
            return this;
        }
        /// <summary>
        /// 开始拼接数组
        /// </summary>
        void AppendArrayStart(string key) {
            AppendTextElement(key);
            sb.Append(':');
            sb.Append('[');
        }
        /// <summary>
        /// 结束拼接数组
        /// </summary> 
        void AppendArrayEnd() {
            var end = sb[sb.Length - 1];
            if (end == ',') {
                sb[sb.Length - 1] = ']';
            } else {
                sb.Append(']');
            }
            sb.Append(',');
        }
        /// <summary>
        /// 附加一个值为字符串集合的键值对
        /// </summary>
        public JsonStringBuilder AppendArray(string key, IEnumerable<string> val) {
            if (val == null) {
                AppendNull(key);
            } else {
                AppendArrayStart(key);
                foreach (var p in val) {
                    AppendTextElement(p);
                    sb.Append(',');
                }
                AppendArrayEnd();
            }
            return this;
        }
        /// <summary>
        /// 附件一个值为时间集合的键值对
        /// </summary>
        public JsonStringBuilder AppendArray(string key, IEnumerable<DateTime> val) {
            if (val == null) {
                AppendNull(key);
            } else {
                AppendArrayStart(key);
                foreach (var p in val) {
                    AppendTextElement(p.ToString());
                    sb.Append(',');
                }
                AppendArrayEnd();
            }
            return this;
        }
        /// <summary>
        /// 附加一个值为字节数组的键值对,注意,json规则中,如果值是字节数组,就需要把字节数组转成base64字符串
        /// </summary>
        public JsonStringBuilder AppendArray(string key, byte[] val) {
            if (val == null) {
                AppendNull(key);
            } else {
                Append(key, Convert.ToBase64String(val));
            }
            return this;
        }
        /// <summary>
        /// 附加一个值为布尔集合的键值对
        /// </summary>
        public JsonStringBuilder AppendArray(string key, IEnumerable<bool> val) {
            if (val == null) {
                AppendNull(key);
            } else {
                AppendArrayStart(key);
                foreach (var p in val) {
                    sb.Append(p ? "true," : "false,");
                }
                AppendArrayEnd();
            }
            return this;
        }
        /// <summary>
        /// 附加一个值为数值集合的键值对
        /// </summary>
        public JsonStringBuilder AppendArray<T>(string key, IEnumerable<T> val) where T : struct {
            if (val == null) {
                AppendNull(key);
            } else {
                AppendArrayStart(key);
                sb.Append(string.Join(",", val));
                AppendArrayEnd();
            }
            return this;
        }
        /// <summary>
        /// 附加一个值为泛型对象集合的键值对
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">泛型对象集合</param>
        /// <param name="objectAppend">对单以对象的附加操作</param>
        /// <returns>当前操作的json构建者对象</returns>
        public JsonStringBuilder AppendArray<T>(string key, IEnumerable<T> val, Action<JsonStringBuilder, T> objectAppend) where T : class {
            if (val == null) {
                AppendNull(key);
            } else {
                AppendArrayStart(key);
                foreach (var p in val) {
                    sb.Append('{');  //这个地方有些特殊,不能直接用AppendArrayStart
                    objectAppend(this, p);
                    AppendObjectEnd();
                }
                AppendArrayEnd();
            }
            return this;
        }
        /// <summary>
        /// 得到json字符串
        /// </summary>
        public override string ToString() {
            sb[sb.Length - 1] = '}';
            return sb.ToString(); ;
        }
        /// <summary>
        /// 重置以作复用
        /// </summary>
        public void Reset() {
            sb.Clear();
            sb.Append('{');
        }
    }
View Code
复制代码

测试代码

复制代码
        public void Test() {
            /*
             * 一般用于比较简单的使用场景,不使用模型或者匿名类通过第三方库转,自己自己拼接,
             * 性能是Newtonsoft.Json的2-3倍
             * */
            var json = new JsonStringBuilder()
                .Append("errcode", 1001)
                .Append("errmsg", "ok")
                .Append("msgid", 1).ToString();
            Console.WriteLine(json);

            /*
             * 目前也支持子对象和数组了,如果数据结构很复杂,还是建议使用Newtonsoft.Json,
             * 因为手动拼接太繁琐了
             * */
            var user = CreateUser();
            var json_jsb = ByJsb(user); 
            var json_newtonsoft = ByNewtonsoft(user);
            Console.WriteLine(json_jsb);
            Console.WriteLine(json_newtonsoft);
            Console.WriteLine(json_jsb == json_newtonsoft);  //使用Newtonsoft.Json对比数据完全一致
        }
View Code
复制代码

和Newtonsoft.Json对比数据的一致性

复制代码
        class User {
            public int ID;
            public string Name;
            public ushort Age;
            public bool Married;
            public byte[] Photo;
            public User Father;
            public List<User> Friends;
            public bool[] TaskState;
            public List<DateTime> TaskTime;
            public List<string> TaskDesc;
            public int[] TaskGrade;
            public DateTime RecordTime;
        }
        /// <summary>
        /// 创建测试数据
        /// </summary>
        User CreateUser() {
            User user; user = new User() {
                ID = 1,
                Name = "张三",
                Age = 18,
                Married = false,
                Photo = new byte[10],
                Father = new User {
                    ID = 6,
                    Name = "张大山",
                    RecordTime = DateTime.Now,
                },
                Friends = new List<User>{
                    new User{
                        ID = 2,
                        Name = "李四",
                        RecordTime = DateTime.Now,
                    },
                    new User{
                        ID  =3,
                        Name = "王五",
                        RecordTime = DateTime.Now,
                    }
                },
                TaskState = new bool[10],
                TaskTime = new List<DateTime>(),
                TaskDesc = new List<string>(),
                TaskGrade = new int[10],
                RecordTime = DateTime.Now,
            };
            new Random().NextBytes(user.Photo);
            for (int i = 0; i < 10; i++) {
                user.TaskState[i] = i % 2 == 0;
                user.TaskTime.Add(DateTime.Now.AddDays(-i));
                user.TaskDesc.Add(Guid.NewGuid().ToString());
                user.TaskGrade[i] = i;
            }
            return user;
        }

        string ByNewtonsoft(User user) {
            return JsonHelper.GetJson(user);
        }
        string ByJsb(User user) {
            return BuildUserJson(new JsonStringBuilder(), user).ToString();
        }
        JsonStringBuilder BuildUserJson(JsonStringBuilder jb, User user) {
            return jb.Append("ID", user.ID)
               .Append("Name", user.Name)
               .Append("Age", user.Age)
               .Append("Married", user.Married)
               .AppendArray("Photo", user.Photo)
               .Append("Father", user.Father, p => {
                   BuildUserJson(p, user.Father);
               }).AppendArray("Friends", user.Friends, (p, val) => {
                   BuildUserJson(p, val);
               }).AppendArray("TaskState", user.TaskState)
                .AppendArray("TaskTime", user.TaskTime)
                .AppendArray("TaskDesc", user.TaskDesc)
                .AppendArray("TaskGrade", user.TaskGrade)
                .Append("RecordTime", user.RecordTime);
        }
    }
View Code
复制代码

 

之前的旧版本(功能非常简单)

复制代码
using System;
using System.Text;

namespace ConsoleApp {
    /// <summary>
    /// 简单的json字符串构建类,只支持单层基础类型字段,不支持数组,对象等字段
    /// </summary>
    public class JsonStringBuilder {
        readonly StringBuilder sb = new StringBuilder("{");
        public void Append(string key, string val, bool hasMark) {
            if (hasMark) {
                sb.Append($"\"{key}\":\"{val}\",");
            } else {
                sb.Append($"\"{key}\":{val},");
            }
        }
        public void Append(string key, string val) {
            Append(key, val, true);
        }
        public void Append(string key, DateTime val) {
            Append(key, val.ToString(), true);
        }
        public void Append<T>(string key, T val) where T : struct {
            Append(key, val.ToString(), false);
        }
        public override string ToString() {
            sb[sb.Length - 1] = '}';
            string json = sb.ToString();
            sb[sb.Length - 1] = ','; //不破坏原字符组,因为可能会继续Append
            return json;
        }
    }
}
View Code
复制代码

测试代码

复制代码
        static void Test() {
            int id = 1;
            string name = "张三";
            DateTime birthDate = new DateTime(1989, 6, 8);
            //一些比较简单的json结构没必要使用模型或者匿名类通过json库进行转换
            SpeedTester.Start(5, () => { //一个速度测试函数,用来对比自己拼和封装拼接的运行速度差距
                //但是手动拼比较麻烦,特别是双引号,处理器起来很麻烦,但是性能最好
                string json = "{\"ID\":" + id + ",\"Name\":\"" + name + "\",\"BirthDate\":\"" + birthDate + "\"}";
            }, () => {
                //稍微封装一下,这样就不用关系双引号的问题了,性能也比json库快很多
                JsonStringBuilder jsb = new JsonStringBuilder();
                jsb.Append("ID", id);
                jsb.Append("Name", name);
                jsb.Append("BirthDate", birthDate);
                string json = jsb.ToString();
                Log.Info(json);
            });
        }
View Code
复制代码

 

posted @   WmW  阅读(154)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示