将 JToken 显式转换为带有错误 "possible null reference return" 警告的字符串
Explicit conversion of JToken to string with false "possible null reference return" warning
我正在使用 C#10、Newtonsoft.Json 和可为 null 的引用类型。我围绕 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;
}
}
如您所见,我在 SelectTokenAsString
方法中添加了注释。为什么 Visual Studio 用绿色波浪线在这一行下划线,并认为可能存在空引用 return 并可能转换为空?很明显,SelectToken 方法永远不会 return null。有趣的是,VS 认为 SelectTokenAsInt
方法完全没问题。
将 JToken
转换为 string
实际上是 returns string?
(see public static explicit operator string?(JToken? value)
)。所以警告是关于将 JToken
转换为 string
的结果而不是 SelectToken
的结果(我假设这种行为的原因可能是处理 null
json 令牌)。
您可以尝试使用 JToken.ToString
重载(它在内部调用 JToken.ToString(Formatting.Indented)
所以它可能不会给出您期望的结果):
public string SelectTokenAsString(string jsonPath) => SelectToken(jsonPath).ToString();
Guru Stron 的回答是正确的,但我想提供更多解释。
如果你进一步分解你的代码,下面是那一行发生的事情:
JToken token = SelectToken(jsonPath); // no warning
return (string)token!; // warning
因此,即使您的 SelectToken
方法不是 return 可空类型,将该 JToken 转换为 string
也可能 return 空值,由于执行该转换的隐式运算符。请记住,null
是一个有效的 JSON 标记,因此以下代码将为您提供一个 null
值,即使您确保 JToken?
不为空的检查通过并且不会抛出异常。
string? foo = new JsonWrapper(@"{""foo"": null}").SelectTokenAsString("foo");
您最好再做一次空值检查,以确保您不会得到这样的空字符串:
JToken token = SelectToken(jsonPath);
return (string?)token ?? throw new InvalidCastException($"Token value at path {jsonPath} was null");
我正在使用 C#10、Newtonsoft.Json 和可为 null 的引用类型。我围绕 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;
}
}
如您所见,我在 SelectTokenAsString
方法中添加了注释。为什么 Visual Studio 用绿色波浪线在这一行下划线,并认为可能存在空引用 return 并可能转换为空?很明显,SelectToken 方法永远不会 return null。有趣的是,VS 认为 SelectTokenAsInt
方法完全没问题。
将 JToken
转换为 string
实际上是 returns string?
(see public static explicit operator string?(JToken? value)
)。所以警告是关于将 JToken
转换为 string
的结果而不是 SelectToken
的结果(我假设这种行为的原因可能是处理 null
json 令牌)。
您可以尝试使用 JToken.ToString
重载(它在内部调用 JToken.ToString(Formatting.Indented)
所以它可能不会给出您期望的结果):
public string SelectTokenAsString(string jsonPath) => SelectToken(jsonPath).ToString();
Guru Stron 的回答是正确的,但我想提供更多解释。
如果你进一步分解你的代码,下面是那一行发生的事情:
JToken token = SelectToken(jsonPath); // no warning
return (string)token!; // warning
因此,即使您的 SelectToken
方法不是 return 可空类型,将该 JToken 转换为 string
也可能 return 空值,由于执行该转换的隐式运算符。请记住,null
是一个有效的 JSON 标记,因此以下代码将为您提供一个 null
值,即使您确保 JToken?
不为空的检查通过并且不会抛出异常。
string? foo = new JsonWrapper(@"{""foo"": null}").SelectTokenAsString("foo");
您最好再做一次空值检查,以确保您不会得到这样的空字符串:
JToken token = SelectToken(jsonPath);
return (string?)token ?? throw new InvalidCastException($"Token value at path {jsonPath} was null");