C# Parse JSON One by One

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

痴者工良

高级程序员劝退师

文章评论