Search code examples
c#jsonasp.net-coresystem.text.json

Why doesn't System.Text.Json.JsonElement have TryGetString() or TryGetBoolean()


I'm parsing some JSON data with the .NET Core System.Text.Json namespace which returns JsonElement objects.

For Int32 types, for example, JsonElement has a GetInt32() which will return the value as an integer or throw an exception if it isn't an integer, and there is also a TryGetInt32() which copies the parsed value to an out variable and returns true or false depending on whether it was able to parse correctly.

The same applies to almost all other primitive types but for some reason, GetBoolean() and GetString() have no try... equivalent even though they also will throw an exception if the value cannot be parsed correctly.

This seems such an obvious oversight, it makes me think I'm doing something wrong. Can anyone explain why they aren't needed?


Solution

  • UPD

    Don't mind the original answer, the TryGet_number_type methods don't work as I (and I assume you) would expect - they will throw if you will try to get "number_type" from element which ValueKind is not a Number (decimal docs for example).

    So this TryGet... API basically tries to parse inner value as some concrete type but only if value is of valid json type for this attempted concrete type(Number for all numeric types, String for Guid, DateTime and DateTimeOffset), otherwise it will throw InvalidOperationException, therefore it would not make sense to have an TryGetString and TryGetBoolean methods because there is no ambiguity here (string is always a string and boolean is always a boolean) and they would behave exactly the same as Get counterpart.

    Original answer:

    Was not able to find any reasoning for not having this API's, but implementing them yourself should not be a big issue (still would be nice to have them in standard library):

    According to docs GetBoolean throws if value's ValueKind is neither True nor False.

    public static bool TryGetBoolean(this JsonElement je, out bool parsed)
    {
        var (p, r) = je.ValueKind switch
        {
            JsonValueKind.True => (true, true),
            JsonValueKind.False => (false, true),
            _ => (default, false)
        };    
        parsed = p;
        return r;
    }
    

    And GetString throws if value's ValueKind is neither String nor Null:

    public static bool TryGetsString(this JsonElement je, out string parsed)
    {
        var (p, r) = je.ValueKind switch
        {
            JsonValueKind.String => (je.GetString(), true),
            JsonValueKind.Null => (null, true),
            _ => (default, false)
        };  
        parsed = p;
        return r;
    }
    

    And sample test:

    using (JsonDocument document = JsonDocument.Parse(@"{""bool"": true, ""str"": ""string""}"))
    {
        if (document.RootElement.GetProperty("bool").TryGetBoolean(out var b))
        {
            Console.WriteLine(b);
        }
    
        if (document.RootElement.GetProperty("str").TryGetString( out var s))
        {
            Console.WriteLine(s);
        }
    }