面向云技术架构 - 痴者工良

  • 首页
  • 工良写的电子书
    • kubernetes 教程
    • 从 C# 入门 Kafka
    • 多线程和异步
    • 动态编程-反射、特性、AOP
    • 表达式树
  • 本站文章导航
  • 隐私政策
愿有人陪你颠沛流离
遇到能让你付出的事物或者人,都是一种运气。
能遇到,就该珍惜。或许你们最终没能在一起,但你会切实地感受到力量。
正因为这样,那段相遇才变得有价值,才没有辜负这世间的每一段相遇。
  1. 首页
  2. .NET
  3. 正文

C# 逐个解析 JSON

2022年10月24日 384点热度 1人点赞 0条评论
内容纲要

后面改进了对象池算法,使用结构体来存储,其性能变得非常强。
参考对象池算法:https://www.whuanle.cn/archives/20888

新版本

定义结构体存储每个字段:

public struct JsonField
{
    public string? Name
    {
        get; set;
    }
    public JsonValueKind ValueKind
    {
        get; set;
    }
    public object? Value
    {
        get; set;
    }

    public string? Key
    {
        get; set;
    }
}

定义静态类:

public static class JsonParseTool
{

}

解析字段:

    // 解析 json 字段
    private static object? ReadObject(ref Utf8JsonReader reader, ref JsonField field)
    {
        switch (reader.TokenType)
        {
            case JsonTokenType.Null or JsonTokenType.None:
                field.ValueKind = JsonValueKind.Null;
                return null;
            case JsonTokenType.False:
                field.ValueKind = JsonValueKind.False;
                return reader.GetBoolean();
            case JsonTokenType.True:
                field.ValueKind = JsonValueKind.True;
                return reader.GetBoolean();
            case JsonTokenType.Number:
                field.ValueKind = JsonValueKind.Number;
                return reader.GetDouble();
            case JsonTokenType.String:
                field.ValueKind = JsonValueKind.String;
                return reader.GetString() ?? "";
            default: return null;
        }
    }

解析数组:

    private static void ParseArray(ObjectPool pool,
    ref Utf8JsonReader reader,
    Dictionary<string, JsonField> map,
    string? baseKey)
    {
        var i = 0;
        while (reader.Read())
        {
            if (reader.TokenType is JsonTokenType.EndArray) break;
            var newkey = baseKey is null ? $"[{i}]" : $"{baseKey}[{i}]";
            i++;

            ref var field = ref pool.Get();
            field.Key = newkey;
            map[newkey] = field;

            switch (reader.TokenType)
            {
                // [...,null,...]
                case JsonTokenType.Null:
                    field.ValueKind = JsonValueKind.Null;
                    break;
                // [...,123.666,...]
                case JsonTokenType.Number:
                    field.ValueKind = JsonValueKind.Number;
                    field.Value = reader.GetDouble();
                    break;
                // [...,"123",...]
                case JsonTokenType.String:
                    field.ValueKind = JsonValueKind.String;
                    field.Value = reader.GetString();
                    break;
                // [...,true,...]
                case JsonTokenType.True:
                    field.ValueKind = JsonValueKind.True;
                    field.Value = reader.GetBoolean();
                    break;
                case JsonTokenType.False:
                    field.ValueKind = JsonValueKind.False;
                    field.Value = reader.GetBoolean();
                    break;
                // [...,{...},...]
                case JsonTokenType.StartObject:
                    field.ValueKind = JsonValueKind.Object;
                    BuildJsonField(pool, ref reader, ref field, map, newkey);
                    break;
                // [...,[],...]
                case JsonTokenType.StartArray:
                    field.ValueKind = JsonValueKind.Array;
                    ParseArray(pool, ref reader, map, newkey);
                    break;
                default:
                    field.ValueKind = JsonValueKind.Null;
                    break;
            }
        }
    }

解析对象:

    private static void BuildJsonField(
    ObjectPool pool,
    ref Utf8JsonReader reader,
    ref JsonField root,
    Dictionary<string, JsonField> map,
    string? baseKey)
    {
        while (reader.Read())
        {
            // 顶级数组 "[123,123]"
            if (reader.TokenType is JsonTokenType.StartArray)
            {
                root.Key = baseKey;
                root.ValueKind = JsonValueKind.Array;
                ParseArray(pool, ref reader, map, baseKey);
            }
            else if (reader.TokenType is JsonTokenType.EndObject) break;
            else if (reader.TokenType is JsonTokenType.PropertyName)
            {
                var key = reader.GetString()!;
                var newkey = baseKey is null ? key : $"{baseKey}.{key}";
                ref JsonField field = ref pool.Get();
                field.Name = key;
                field.Key = newkey;
                map[newkey] = field;

                reader.Read();
                if (reader.TokenType is JsonTokenType.StartArray)
                {
                    field.ValueKind = JsonValueKind.Array;
                    // 进入数组处理
                    ParseArray(pool, ref reader, map, newkey);
                }
                else if (reader.TokenType is JsonTokenType.StartObject)
                {
                    field.ValueKind = JsonValueKind.Object;
                    BuildJsonField(pool, ref reader, ref field, map, newkey);
                }
                else
                {
                    field.Value = ReadObject(ref reader, ref field);
                }
            }
        }
    }

进入解析:

    public static Dictionary<string, JsonField> Read(
        JsonFieldMemoryPool memoryPool,
        ReadOnlySequence<byte> sequence,
        JsonReaderOptions jsonReaderOptions)
    {
        var reader = new Utf8JsonReader(sequence, jsonReaderOptions);
        var map = new Dictionary<string, JsonField>();
        ref JsonField root = ref memoryPool.Get();
        root.ValueKind = JsonValueKind.Object;
        map["/"] = root;
        BuildJsonField(memoryPool, ref reader, ref root, map, null);
        return map;
    }

旧版本

下面用到一个对象池算法,类型 JsonFieldMemoryPool,也可以改成 new Object 的方式。

每个字段的模型:

public record JsonField
{
    public string? Name { get; set; }
    public JsonValueKind ValueKind { get; set; }
    public object? Value { get; set; }

    public string? Key { get; set; }
}

解析一个字段:

    // 解析 json 字段
    private static object? ReadObject(ref Utf8JsonReader reader, JsonField field)
    {
        switch (reader.TokenType)
        {
            case JsonTokenType.Null or JsonTokenType.None:
                field.ValueKind = JsonValueKind.Null;
                return null;
            case JsonTokenType.False:
                field.ValueKind = JsonValueKind.False;
                return reader.GetBoolean();
            case JsonTokenType.True:
                field.ValueKind = JsonValueKind.True;
                return reader.GetBoolean();
            case JsonTokenType.Number:
                field.ValueKind = JsonValueKind.Number;
                return reader.GetDouble();
            case JsonTokenType.String:
                field.ValueKind = JsonValueKind.String;
                return reader.GetString() ?? "";
            default: return null;
        }
    }

解析数组:

    private static void ParseArray(JsonFieldMemoryPool pool,
        ref Utf8JsonReader reader,
        Dictionary<string, JsonField> map,
        string? baseKey)
    {
        int i = 0;
        while (reader.Read())
        {
            if (reader.TokenType is JsonTokenType.EndArray) break;
            var newkey = baseKey is null ? $"[{i}]" : $"{baseKey}[{i}]";
            i++;

            var field = pool.Get();
            field.Key = newkey;
            map[newkey] = field;

            switch (reader.TokenType)
            {
                // [...,null,...]
                case JsonTokenType.Null:
                    field.ValueKind = JsonValueKind.Null;
                    break;
                // [...,123.666,...]
                case JsonTokenType.Number:
                    field.ValueKind = JsonValueKind.Number;
                    field.Value = reader.GetDouble();
                    break;
                // [...,"123",...]
                case JsonTokenType.String:
                    field.ValueKind = JsonValueKind.String;
                    field.Value = reader.GetString();
                    break;
                // [...,true,...]
                case JsonTokenType.True:
                    field.ValueKind = JsonValueKind.True;
                    field.Value = reader.GetBoolean();
                    break;
                case JsonTokenType.False:
                    field.ValueKind = JsonValueKind.False;
                    field.Value = reader.GetBoolean();
                    break;
                // [...,{...},...]
                case JsonTokenType.StartObject:
                    field.ValueKind = JsonValueKind.Object;
                    BuildJsonField(pool, ref reader, field, map, newkey);
                    break;
                // [...,[],...]
                case JsonTokenType.StartArray:
                    field.ValueKind = JsonValueKind.Array;
                    ParseArray(pool, ref reader, map, newkey);
                    break;
                default:
                    field.ValueKind = JsonValueKind.Null;
                    break;
            }
        }
    }

解析对象:

    private static void BuildJsonField(
        JsonFieldMemoryPool pool,
        ref Utf8JsonReader reader,
        JsonField root,
        Dictionary<string, JsonField> map,
        string? baseKey)
    {
        while (reader.Read())
        {
            // 顶级数组 "[123,123]"
            if (reader.TokenType is JsonTokenType.StartArray)
            {
                root.Key = baseKey;
                root.ValueKind = JsonValueKind.Array;
                ParseArray(pool, ref reader, map, baseKey);
            }
            else if (reader.TokenType is JsonTokenType.EndObject) break;
            else if (reader.TokenType is JsonTokenType.PropertyName)
            {
                var key = reader.GetString()!;
                var newkey = baseKey is null ? key : $"{baseKey}.{key}";
                JsonField field = pool.Get();
                field.Name = key;
                field.Key = newkey;
                map[newkey] = field;

                reader.Read();
                if (reader.TokenType is JsonTokenType.StartArray)
                {
                    field.ValueKind = JsonValueKind.Array;
                    // 进入数组处理
                    ParseArray(pool, ref reader, map, newkey);
                }
                else if (reader.TokenType is JsonTokenType.StartObject)
                {
                    field.ValueKind = JsonValueKind.Object;
                    BuildJsonField(pool, ref reader, field, map, newkey);
                }
                else
                {
                    field.Value = ReadObject(ref reader, field);
                }
            }
        }
    }

进入解析:

    public static Dictionary<string, JsonField> Read(
        JsonFieldMemoryPool memoryPool,
        ReadOnlySequence<byte> sequence,
        JsonReaderOptions jsonReaderOptions)
    {
        var reader = new Utf8JsonReader(sequence, jsonReaderOptions);
        var map = new Dictionary<string, JsonField>();
        JsonField root = memoryPool.Get();
        root.ValueKind = JsonValueKind.Object;
        map["/"] = root;
        BuildJsonField(memoryPool, ref reader, root, map, null);
        return map;
    }
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: c json 解析 逐个
最后更新:2022年10月25日

痴者工良

高级程序员劝退师

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

文章目录
  • 新版本
  • 旧版本

COPYRIGHT © 2022 whuanle.cn. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备18051778号

粤公网安备 44030902003257号