C# 逐个解析 JSON

2022年10月24日 1514点热度 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;
    }

痴者工良

高级程序员劝退师

文章评论