Home > Back-end >  Explicit conversion of JToken to string with false "possible null reference return" warnin
Explicit conversion of JToken to string with false "possible null reference return" warnin

Time:03-11

I'm using C#10, Newtonsoft.Json and nullable reference types. I made a simple wrapper around JObject:

public class JsonWrapper
{
    readonly JObject j;
    public JsonWrapper(string json)
    {  
        j = JObject.Parse(json);
    }

    public string SelectTokenAsString(string jsonPath)
    {
        // 1st warning: Possible null reference return
        // 2nd warning: Converting null literal or possible null value to non-nullable 
        return (string)SelectToken(jsonPath);
    }

    public int SelectTokenAsInt(string jsonPath)
    {
        return (int)SelectToken(jsonPath);
    }

    JToken SelectToken(string jsonPath)
    {
        if (jsonPath == null) throw new ArgumentNullException(nameof(jsonPath));
        JToken? result = j.SelectToken(jsonPath);
        if (result == null) throw new MyException("Bla-bla-bla");
        return result;
    }
}

As you can see I put comments in SelectTokenAsString method. Why Visual Studio underline this row with green wiggily line and thinks there are possible null reference return and possible conversion to null? It's pretty clear that SelectToken method is never return null. Interestingly that VS thinks that SelectTokenAsInt method is totally ok which it is.

CodePudding user response:

Casting JToken to string actually returns string? (see public static explicit operator string?(JToken? value)). So warning is raised about the result of casting JToken to string not the result of SelectToken (I assume the reason for such behaviour can be handling of null json token).

You can try using JToken.ToString overload (which internally calls JToken.ToString(Formatting.Indented) so potentially it can give not the result you expect):

public string SelectTokenAsString(string jsonPath) => SelectToken(jsonPath).ToString();

CodePudding user response:

Guru Stron's answer is correct, but I wanted to provide a little more explanation.

If you break your code down a little further, here's what's happening on that line:

    JToken token = SelectToken(jsonPath); // no warning
    return (string)token!; // warning

So even though your SelectToken method doesn't return a nullable type, the conversion of that JToken into a string might return a null value, due to the implicit operator that performs that conversion. Remember that null is a valid JSON token, so the following code would give you a null value, even though your check to ensure the JToken? isn't null passes and doesn't throw an exception.

string? foo = new JsonWrapper(@"{""foo"": null}").SelectTokenAsString("foo");

You're probably better off doing one more null check to make sure you don't end up with a null string like this:

    JToken token = SelectToken(jsonPath);
    return (string?)token ?? throw new InvalidCastException($"Token value at path {jsonPath} was null");
  • Related