90

我想知道ToObject<>()System.Text.Json 的 Json.NET 中的方法的等价物。

使用 Json.NET,您可以使用任何JToken并将其转换为类。例如:

var str = ""; // some json string
var jObj = JObject.Parse(str);
var myClass = jObj["SomeProperty"].ToObject<SomeClass>();

我们如何能够使用 .NET Core 3 的新功能做到这一点System.Text.Json

var str = ""; // some json string
var jDoc = JsonDocument.Parse(str);
var myClass = jDoc.RootElement.GetProperty("SomeProperty"). <-- now what??

最初我想我只是将JsonElement返回的字符串转换jDoc.RootElement.GetPRoperty("SomeProperty")为字符串,然后反序列化该字符串。但我觉得这可能不是最有效的方法,而且我真的找不到其他方式的文档。

4

4 回答 4

86

我遇到了同样的问题,所以我写了一些现在可以正常工作的扩展方法。如果他们将其作为内置提供以避免额外分配给字符串,那就太好了。

public static T ToObject<T>(this JsonElement element)
{
    var json = element.GetRawText();
    return JsonSerializer.Deserialize<T>(json);
}
public static T ToObject<T>(this JsonDocument document)
{
    var json = document.RootElement.GetRawText();
    return JsonSerializer.Deserialize<T>(json);
}

然后使用如下:

jDoc.RootElement.GetProperty("SomeProperty").ToObject<SomeClass>();
于 2019-10-01T22:40:34.597 回答
80

在 .NET 6中,扩展方法被添加到JsonSerializer直接从 aJsonElement或反序列化对象JsonDocument

public static partial class JsonSerializer
{
    public static TValue? Deserialize<TValue>(this JsonDocument document, JsonSerializerOptions? options = null);
    public static object? Deserialize(this JsonDocument document, Type returnType, JsonSerializerOptions? options = null);
    public static TValue? Deserialize<TValue>(this JsonDocument document, JsonTypeInfo<TValue> jsonTypeInfo);
    public static object? Deserialize(this JsonDocument document, Type returnType, JsonSerializerContext context);

    public static TValue? Deserialize<TValue>(this JsonElement element, JsonSerializerOptions? options = null);
    public static object? Deserialize(this JsonElement element, Type returnType, JsonSerializerOptions? options = null);
    public static TValue? Deserialize<TValue>(this JsonElement element, JsonTypeInfo<TValue> jsonTypeInfo);
    public static object? Deserialize(this JsonElement element, Type returnType, JsonSerializerContext context);
}

现在您将能够:

using var jDoc = JsonDocument.Parse(str);
var myClass = jDoc.RootElement.GetProperty("SomeProperty").Deserialize<SomeClass>();

笔记:

  • JsonDocument是一次性的。根据文档此类利用池内存中的资源......未能正确处理此对象将导致内存未返回到池中,这将增加框架各个部分的 GC 影响。

    所以,一定要声明你jDocusing声明。

  • 新方法应该出现在.NET 6.0 Preview RC1中。

    它们是为了响应增强请求而添加的。我们应该能够从已关闭的 DOM #31274 进行序列化和序列化。

在 .NET 5 和更早版本中,这些方法不存在。作为一种解决方法,您可以通过写入中间byte缓冲区而不是字符串来获得更好的性能,因为两者都JsonDocument直接Utf8JsonReader使用byte跨度而不是字符串或char跨度。如文档中所述:

序列化为 UTF-8 比使用基于字符串的方法快 5-10%。不同之处在于字节(作为 UTF-8)不需要转换为字符串(UTF-16)。

public static partial class JsonExtensions
{
    public static T ToObject<T>(this JsonElement element, JsonSerializerOptions options = null)
    {
        var bufferWriter = new ArrayBufferWriter<byte>();
        using (var writer = new Utf8JsonWriter(bufferWriter))
            element.WriteTo(writer);
        return JsonSerializer.Deserialize<T>(bufferWriter.WrittenSpan, options);
    }

    public static T ToObject<T>(this JsonDocument document, JsonSerializerOptions options = null)
    {
        if (document == null)
            throw new ArgumentNullException(nameof(document));
        return document.RootElement.ToObject<T>(options);
    }       
}

演示小提琴在这里

于 2019-11-26T08:55:00.127 回答
10

dbc 的 answer相同,仅包括允许您通过指定返回类型的方法Type returnType

public static partial class JsonExtensions
{
    public static T ToObject<T>(this JsonElement element, JsonSerializerOptions options = null)
    {
        var bufferWriter = new ArrayBufferWriter<byte>();
        using (var writer = new Utf8JsonWriter(bufferWriter))
        {
            element.WriteTo(writer);
        }

        return JsonSerializer.Deserialize<T>(bufferWriter.WrittenSpan, options);
    }

    public static T ToObject<T>(this JsonDocument document, JsonSerializerOptions options = null)
    {
        if (document == null)
        {
            throw new ArgumentNullException(nameof(document));
        }

        return document.RootElement.ToObject<T>(options);
    }       

    public static object ToObject(this JsonElement element, Type returnType, JsonSerializerOptions options = null)
    {
        var bufferWriter = new ArrayBufferWriter<byte>();
        using (var writer = new Utf8JsonWriter(bufferWriter))
        {
            element.WriteTo(writer);
        }

        return JsonSerializer.Deserialize(bufferWriter.WrittenSpan, returnType, options);
    }

    public static object ToObject(this JsonDocument document, Type returnType, JsonSerializerOptions options = null)
    {
        if (document == null)
        {
            throw new ArgumentNullException(nameof(document));
        }

        return document.RootElement.ToObject(returnType, options);
    }       
}
于 2020-04-05T18:43:20.753 回答
1

.NET 6引入了System.Text.Json.Nodes命名空间,它提供了一种使用与 Json.Net 几乎完全相同的语法来执行此操作的方法:

var str = ""; // some json string
var node = JsonNode.Parse(str);
var myClass = node["SomeProperty"].Deserialize<SomeClass>();

命名空间包括 4 种新类型:JsonNodeJsonArrayJsonObjectJsonValue可用于访问或修改 DOM 中的值。JsonNode是其他三种类型的基类。

dbc 的答案Deserialize中列出的扩展方法也已添加到操作上,例如:JsonNode

public static TValue? Deserialize<TValue>(this JsonNode? node, JsonSerializerOptions? options = null);

JsonNode不是一次性的,因此您不需要使用using语法。

分别使用AsObject()orAsArray()解析为JsonObjector JsonArray

// parse array
JsonArray arr = JsonNode.Parse(@"[{""Name"": ""Bob"", ""Age"":30}]").AsArray();
// parse object
JsonObject obj = JsonNode.Parse(@"{""Name"": ""Bob"", ""Age"":30}").AsObject();
// get a value
var date = JsonNode.Parse(@"{""Date"":""2021-12-21T13:24:46+04:00""}")["Date"].GetValue<DateTimeOffset>();

一旦 json 被解析,就可以导航、过滤和转换 DOM 和/或应用于Deserialize<T>()映射到您的具体类型。

要序列化回 json 字符串,您可以使用ToJsonString(),例如:

string innerNodeJson = node["SomeProperty"].ToJsonString();

有关更多详细信息,请参阅System.Text.Json 中 JObject 等效项的JsonObject答案。

于 2022-02-18T11:56:36.933 回答