NullValueHandling.Ignore影响反序列化到[ExtensionData]尽管匹配类成员

时间:2016-01-25 14:49:08

标签: c# serialization json.net

我的服务器响应包含一组已知和未知的属性。对于已知的,我创建了一个DTO类,其中包含每个属性的成员。未知属性应放在使用[ExtensionData]属性注释的字典中:

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class Dto
{

    [JsonExtensionData]
    private readonly Dictionary<string, object> unknownProperties = new Dictionary<string, object>();

    public IDictionary<string, object> UnknownProperties
    {
        get
        {
            return new ReadOnlyDictionary<string, object>(this.unknownProperties);
        }
    }

    [JsonProperty(Required = Required.Default, PropertyName = "KNOWN_PROPERTY")]
    public string KnownProperty { get; private set; }
}
允许

Null作为KnownProperty的值。如果我尝试反序列化包含KNOWN_PROPERTY : null的JSON对象,如果我使用UnknownProperties配置序列化程序,则此属性也包含在字典NullValueHandling.Ignore中。即使KNOWN_PROPERTY

存在类成员,也会执行此操作
static void Main(string[] args)
{
   string jsonString = @"{
          KNOWN_PROPERTY : null,
          UNKNOWN_PROPERTY : null
   }";

   JsonSerializer serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings()
   {
       NullValueHandling = NullValueHandling.Ignore
    });

    using (var textReader = new StringReader(jsonString))
    {
       Dto dto = serializer.Deserialize<Dto>(new JsonTextReader(textReader));
       foreach (var pair in dto.UnknownProperties)
       {
           Console.WriteLine("{0}: {1}", pair.Key, pair.Value == null ? "null" : pair.Value.ToString());
        }
    }
 }

输出:

 KNOWN_PROPERTY : null
 UNKNOWN_PROPERTY : null

如果我使用NullValueHandling.Include配置序列化程序或在JSON字符串中为KNOWN_PROPERTY设置值,则字典仅按预期包含UNKNOWN_PROPERTY

据我所知[ExtensionData]如果将NullValueHandling设置为忽略,则无法正常工作,因为documentation表示仅在未找到匹配的类成员时才使用扩展名。

我看到的行为是什么意思?我可以做些什么来避免这种情况吗?由于我不想将空值发送到服务器,因此我想坚持使用当前设置的NullValueHandling

我正在使用Json.NET 8.0.2

1 个答案:

答案 0 :(得分:5)

<强>更新

JsonExtensionData should not include the null values that are real object properties. #1719中报告并在提交e079301中修复。修复程序应该包含在11.0.2之后的Json.NET的下一个版本中。

原始答案

确认 - 在JsonSerializerInternalReader.PopulateObject(object, JsonReader, JsonObjectContract, JsonProperty, string)中有以下逻辑:

first-class

如果要忽略属性,则意图似乎是将值放入扩展数据中,但如果值将被忽略 - 一个略有不同的概念。我同意这可能是一个错误。您可能需要report it

有一种解决方法。 Json.NET有两个属性,这些属性会影响null / default值的序列化方式:

  • NullValueHandling。指定在序列化和反序列化对象时包含或忽略空值。值为// set extension data if property is ignored or readonly if (!SetPropertyValue(property, propertyConverter, contract, member, reader, newObject)) { SetExtensionData(contract, member, reader, memberName, newObject); } Include

  • DefaultValueHandling。这有更复杂的语义:

    1. Ignore:在序列化对象时包括成员值与成员的默认值相同的成员。包含的成员将写入JSON。反序列化时没有效果。
    2. Include:在序列化对象时忽略成员值与成员的默认值相同的成员,这样就不会写入JSON。此选项将忽略所有默认值(例如,对象和可空类型为null;对于整数,小数和浮点数为0;对于布尔值为false)。
    3. Ignore:在反序列化时,具有默认值但没有JSON的成员将设置为其默认值。
    4. Populate:在序列化对象时忽略成员值与成员的默认值相同的成员,并在反序列化时将成员设置为默认值。

那么,这些重叠设置如何相互作用?事实证明,Json.NET同时检查它们:如果两个设置都一致则序列化,如果两个设置都令人满意则反序列化。并且IgnoreAndPopulate似乎可以执行您想要的操作 - 它在序列化时省略了空值,但在反序列化时读取并设置它们(如果存在)。

因此,我能够通过以下DefaultValueHandling.IgnoreAndPopulate得到您想要的行为:

JsonProperty

原型fiddle