这是设计使然。
Json.NET 不允许实际的空 JToken 值出现在 JToken 层次结构中,无论是作为 JArray 成员还是 JProperty 值。相反,如果应用程序代码尝试设置或添加 null 令牌,则会将其替换为 非空 JValue,其中 JValue.Type 等于 JTokenType.Null。这种替换发生在例如JContainer.EnsureParentToken(JToken item, bool skipParentCheck):
internal JToken EnsureParentToken(JToken item, bool skipParentCheck)
{
if (item == null)
{
return JValue.CreateNull();
}
还有JProperty.Value:
public JToken Value
{
set
{
CheckReentrancy();
JToken newValue = value ?? JValue.CreateNull();
我相信 Newtonsoft 这样做是为了捕捉以下两个 JSON 对象之间的差异:
{
"field1": null
}
还有空对象:
{ }
在第一种情况下,"field1" 属性与 null JSON 值一起存在。在第二种情况下,属性"field1" 不存在。 Linq-to-JSON 表示第一个具有空类型 JValue 而不是 JProperty.Value 实际上为空的情况。它可能会这样做,因为如果没有,object["field1"] 在这两种情况下都会返回null,这使得它们更难区分。 (与Dictionary<TKey, TValue> 不同,JObject 在尝试访问不存在的属性的值时不会抛出KeyNotFoundException。相反,JObject.Item[String] 会为缺少的键的值返回 null JValue。)
您的代码obj["field1"] = null; 创建了第一种形式的JSON 对象,如果您检查obj.ToString() 的值,您可以看到该对象。因此obj["field1"] 返回非空
如果您不需要区分缺失值和空值属性,您可以引入扩展方法来检查空值,例如 Checking for empty/null JToken in a JObject 或 Issue with JSON null handling in Newtonsoft.