继承Dictionary的自定义类型用System.Text.Json序列化时额外属性丢失如何解决
问题原因
System.Text.Json 对派生自 Dictionary<TKey, TValue> 的类型默认使用专属的字典序列化逻辑,仅输出字典存储的键值对,会自动忽略类本身定义的自定义属性,因此无论是否添加 [JsonInclude] 特性都不会生效。
解决方案
方案一:自定义JsonConverter(推荐,无侵入,无需修改原有类结构)
你只需要实现自定义的序列化转换器,手动处理自定义属性和字典键值对的输出即可:
public class ProductJsonConverter : JsonConverter<Product> { // 无需考虑反序列化,直接抛出异常即可 public override Product Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException(); public override void Write(Utf8JsonWriter writer, Product value, JsonSerializerOptions options) { writer.WriteStartObject(); // 输出自定义属性 writer.WriteString(nameof(Product.ProductId), value.ProductId); // 输出字典内所有键值对 foreach (var (key, val) in value) { writer.WritePropertyName(key); JsonSerializer.Serialize(writer, val, options); } writer.WriteEndObject(); } }
使用时在序列化配置中添加该转换器:
[Fact] public void SimpleTest() { var p = new Product("ABC123"); p["foo"] = "bar"; var options = new JsonSerializerOptions { Converters = { new ProductJsonConverter() }, // 如需驼峰命名可添加以下配置 PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; var json = JsonSerializer.Serialize(p, options); Assert.Contains("productId", json, StringComparison.OrdinalIgnoreCase); }
执行后输出的JSON为:{"productId":"ABC123","foo":"bar"},可通过你的测试用例。
方案二:调整类结构为组合模式(适合允许修改原有设计的场景)
如果可以调整类的实现,不继承Dictionary改为组合的方式,默认序列化就会识别所有属性:
public class Product { public string ProductId { get; set; } public Dictionary<string, object> ExtendFields { get; set; } = new(); public Product(string productId) { ProductId = productId; } // 可选:保留索引器写法,兼容原有代码的访问逻辑 public object this[string key] { get => ExtendFields[key]; set => ExtendFields[key] = value; } }
如果需要将扩展字段提到JSON根节点,还是需要结合自定义Converter实现。
内容的提问来源于stack exchange,提问作者Develorem
相关产品推荐
相关产品推荐

