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

Dev*_*rem 5 c# serialization json .net-5 system.text.json

我有以下类型:

public class Product : Dictionary<string, object>
{
    [JsonInclude]
    public string ProductId { get; set; }

    public Product(string productId) : base()
    {
        ProductId = productId;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用 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);
}
Run Code Online (Sandbox Code Playgroud)

并收到输出:

{"foo":"bar"}
Run Code Online (Sandbox Code Playgroud)

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

dbc*_*dbc 3

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

这可能是因为:

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

作为替代方案,您可以考虑使用不同的数据模型,其中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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

笔记:

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

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

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

  • 在您的问题中,您声明不关心反序列化,但反序列化确实可以与JsonExtensionData.

演示小提琴在这里