web-dev-qa-db-fra.com

Solution de contournement de System.Text.Json.JsonElement ToObject

Je veux connaître l'équivalent de la méthode ToObject<>() dans Json.NET pour System.Text.Json.

En utilisant Json.NET, vous pouvez utiliser n'importe quel JToken et le convertir en classe. PAR EXEMPLE:

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

Comment pourrions-nous faire cela avec le nouveau System.Text.Json De .NET Core 3

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

Au départ, je pensais que je convertirais simplement le JsonElement qui est retourné dans jDoc.RootElement.GetPRoperty("SomeProperty") en une chaîne, puis désérialiser cette chaîne. Mais je pense que ce n'est peut-être pas la méthode la plus efficace, et je ne trouve pas vraiment de documentation pour le faire d'une autre manière.

11
Stalfos

Je suis tombé sur le même problème, j'ai donc écrit quelques méthodes d'extension qui fonctionnent bien pour l'instant. Ce serait bien s'ils fournissaient cela comme intégré pour éviter l'allocation supplémentaire à une chaîne.

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);
}

Ensuite, utilisez comme suit:

jDoc.RootElement.GetProperty("SomeProperty").ToObject<SomeClass>();
7
Gary Holland

Il y a une amélioration ouverte à ce sujet, actuellement ciblée pour . NET Core 5. :

Dans l'intervalle, vous pouvez obtenir de meilleures performances en écrivant dans un tampon intermédiaire byte plutôt que dans une chaîne, car JsonDocument et Utf8JsonReader fonctionne directement avec byte étendues plutôt qu'avec des chaînes ou char étendues:

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);
    }       
}

Violon de démonstration ici .

4
dbc

Identique à la réponse de dbc, en incluant juste les méthodes qui vous permettent de spécifier un returnType dynamique.

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

        return JsonSerializer.Deserialize<T>(bufferWriter.ToArray(), 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 MemoryStream();
        using (var writer = new Utf8JsonWriter(bufferWriter))
        {
            element.WriteTo(writer);
        }

        return JsonSerializer.Deserialize(bufferWriter.ToArray(), 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);
    }       
}
0
Paul