c# - 如何使用System.Text.Json将json数组转换为集合;

标签 c# json system.text.json

我有一个User具有属性的类 Roles类型 ISet<Role> ,其中Roleenum类型。在 JSON 中,我得到该属性的一个数组(例如 "Roles":["Admin","User"] )。我如何编写一个自定义转换器来将此数组转换为 ISet收藏?

我尝试编写这个类:

class CustomStringToRoleConverter : JsonConverter<ISet<User.Role>> {
    public override ISet<User.Role> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
        return null;
    }

    public override void Write(Utf8JsonWriter writer, ISet<User.Role> roles, JsonSerializerOptions options) {
        StringBuilder builder = new StringBuilder();
        builder.Append(string.Join(",", roles.Select(role => role.ToString()).ToArray()));
        writer.WriteStartArray();
        writer.WriteStringValue(builder.ToString());
        writer.WriteEndArray();
    }
}

但我不知道在 Read 做什么方法。如何从 Utf8JsonReader 获取数组?有一个GetString方法,但当我调用它时它抛出异常:

InvalidOperationException: Cannot get the value of a token type 'StartArray' as a string.

我正在使用System.TextSystem.Text.Json .

最佳答案

JSON "Roles":["Admin","User"] property 是字符串值的数组,而不是包含逗号分隔值的单个字符串值。因此,编写自定义转换器的最简单方法如下:

class CustomStringToRoleConverter : JsonConverter<ISet<User.Role>> {
    public override ISet<User.Role> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
        JsonSerializer.Deserialize<List<string>>(ref reader, options)
            ?.Select(s => Enum.Parse<User.Role>(s))
            ?.ToHashSet(); // Or use a SortedSet if you prefer

    public override void Write(Utf8JsonWriter writer, ISet<User.Role> roles, JsonSerializerOptions options) =>
        JsonSerializer.Serialize(writer, roles.Select(r => r.ToString()), options);
}

转换器只是序列化和反序列化字符串集合,然后将项目解析或格式化为 Role枚举作为后处理或预处理步骤。 (为了进行比较,您现有的 Write() 方法将生成 "Roles": ["Admin,User"] ,它与问题开头段落中显示的 JSON 不匹配。)

示例 fiddle #1 here .

如果您非常关心性能并且更喜欢一种不反序列化为中间的更“手动”的方法 List<string> ,你可以这样做:

class CustomStringToRoleConverter : JsonConverter<ISet<User.Role>> {
    public override ISet<User.Role> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
            return null; // Or throw an exception if you don't want to allow null
        else if (reader.TokenType != JsonTokenType.StartArray)
            throw new JsonException();
        var set = new HashSet<User.Role>();
        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndArray)
                return set;
            else if (reader.TokenType == JsonTokenType.String)
                set.Add(Enum.Parse<User.Role>(reader.GetString()));
            else
            {
                //reader.Skip();
                throw new JsonException(); // Unexpected token;
            }
        }
        throw new JsonException(); // Truncated file;
    }

    public override void Write(Utf8JsonWriter writer, ISet<User.Role> roles, JsonSerializerOptions options)
    {
        writer.WriteStartArray();
        foreach (var value in roles)
            writer.WriteStringValue(value.ToString());
        writer.WriteEndArray();
    }
}

示例 fiddle #2 here .

或者,您可以简单地添加 JsonStringEnumConverter JsonSerializerOptions.Converters 将所有枚举序列化为字符串。

关于c# - 如何使用System.Text.Json将json数组转换为集合;,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66750433/

相关文章:

c# - .NET 4.5 HttpClient 请求 ServicePoint

c# - 使用 `ElementName` 的 WPF 绑定(bind)失败,但在 Path 属性中指定 ElementName 有效吗?

javascript - JSON 对象创建和 JSON 数组操作

ios - Alamofire JSON 序列化错误 - Swift 2.0

c# 将韩文字符串保存到文件,而不是utf形式的字符串

javascript - C#和Js之间通过socket发送二进制数据

c# - 错误 CS0117 : 'System.IO.File' does not contain a definition for 'Encrypt'

java - Android - 错误 java.lang.UnsupportedOperationException : JsonNull

c# - 在 JsonDeserializer 中正确跳过父级

c# - C#9 不支持 JsonPropertyNameAttribute 记录?