使用 System.Text.Json 继承字典的自定义类型序列化不会序列化其他属性



我有以下类型:

public class Product : Dictionary<string, object>
{
[JsonInclude]
public string ProductId { get; set; }
public Product(string productId) : base()
{
ProductId = productId;
}
}

当使用System.Text.Json进行序列化时,它不包括属性(即ProductId)。 添加或删除[JsonInclude]似乎没有任何效果。

测试用例:

[Fact]
public void SimpleTest()
{
var p = new Product("ABC123");
p["foo"] = "bar";
var json = JsonSerializer.Serialize(p);
Assert.Contains("productId", json, StringComparison.OrdinalIgnoreCase);
}

和收到的输出:

{"foo":"bar"}

如何使其在序列化期间在我的类型中包含我的自定义属性?(注意:不关心反序列化)。

System.Text.Json不序列化字典属性。我在 MSFT 文档中找不到任何说明这一点的地方,但System.Text.Json只序列化字典键和值。这可以从DictionaryOfTKeyTValueConverter<TCollection, TKey, TValue>的参考源确认,这是用于您的类型的转换器。

这可能是因为:

  1. 可能存在与属性同名的键。
  2. 应用程序开发人员几乎肯定不希望序列化CountIsReadOnly等"标准"字典属性。
  3. 早期的序列化程序的行为方式相同,System.Text.Json遵循先例。 Newtonsoft 被记录为仅序列化字典键和值。DataContractJsonSerializer(UseSimpleDictionaryFormat = true)和JavaScriptSerializer也这样做。

作为替代方案,您可以考虑一个不同的数据模型,其中Product不继承自Dictionary,而是具有[JsonExtensionData] public Dictionary<string, object> Properties { get; set; }属性:

public class Product 
{
public string ProductId { get; set; }
[System.Text.Json.Serialization.JsonExtensionData]
public Dictionary<string, object> Properties { get; set; } = new ();
public Product(string productId) : base()
{
ProductId = productId;
}
}

[JsonExtensionData]属性会导致在序列化和反序列化时将字典属性作为父对象的一部分包含在内。

笔记:

  • 如果建议的替代方法不可接受,则需要编写自定义JsonConverter来手动序列化 .NET 属性以及Product字典的键和值。

  • [JsonInclude]添加到ProductId不会强制对其进行序列化。 根据JsonInclude的文档,当应用于属性时,[它] 表示非公共 getter 和 setter 可用于序列化和反序列化。所以这里无关紧要,因为ProductId已经有公共getter和setter。

  • Newtonsoft也有一个JsonExtensionData属性(它做同样的事情)。 如果同时使用这两个序列化程序,请小心使用正确的属性。

  • 在您的问题中,您说不关心反序列化,但反序列化确实可以正常工作JsonExtensionData.

演示小提琴在这里。

相关内容

最新更新