System.Text.Json序列化ILevel2时未包含ILevel1属性的原因及解决方法
System.Text.Json序列化接口继承属性丢失问题解决
问题原因
System.Text.Json默认只序列化编译时可见的类型成员。当你用ILevel2类型的变量调用序列化时,编译器仅能识别ILevel2自身定义的Scrore属性,不会自动遍历它继承自ILevel1的Name和City——接口的继承关系不会被序列化器自动解析。
解决方案
方案1:指定实际序列化类型
序列化时显式指定对象的实际类型(即FullClass),让序列化器知道要处理所有成员:
// 方式1:使用非泛型重载,传入实际类型 Console.WriteLine(JsonSerializer.Serialize(level2, typeof(FullClass))); // 方式2:使用泛型重载,指定实际类型 Console.WriteLine(JsonSerializer.Serialize<FullClass>(level2));
方案2:用JsonDerivedType标记接口
在ILevel2接口上添加JsonDerivedType特性,告诉序列化器该接口的实际实现类型,这样序列化时会自动包含所有继承的属性:
[JsonDerivedType(typeof(FullClass))] public interface ILevel2 : ILevel1 { int Scrore { get; set; } }
之后直接序列化ILevel2变量就能得到预期结果:
Console.WriteLine(JsonSerializer.Serialize(level2)); // 输出:{"Scrore":10,"Name":"Benjamin","City":"Lille"}
方案3:自定义Json转换器(复杂场景)
如果有多个实现类型,或者需要更灵活的控制,可以自定义转换器遍历接口的所有属性:
public class InterfaceConverter<T> : JsonConverter<T> where T : class { public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { throw new NotImplementedException(); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { var jsonObj = new JsonObject(); // 遍历所有接口的属性 foreach (var prop in value.GetType().GetProperties()) { jsonObj.Add(prop.Name, JsonSerializer.SerializeToElement(prop.GetValue(value), options)); } jsonObj.WriteTo(writer); } }
使用时在序列化选项中添加转换器:
var options = new JsonSerializerOptions(); options.Converters.Add(new InterfaceConverter<ILevel2>()); Console.WriteLine(JsonSerializer.Serialize(level2, options));
原问题代码示例
var obj = new FullClass() { Name = "Benjamin", Scrore = 10, City = "Lille"}; ILevel1 level1 = obj as ILevel1; ILevel2 level2 = obj as ILevel2; Console.WriteLine(JsonSerializer.Serialize(obj)); //==> {"Scrore":10,"Name":"Benjamin","City":"Lille"} Console.WriteLine(JsonSerializer.Serialize(level1)); //==> {"Name":"Benjamin","City":"Lille"} Console.WriteLine(JsonSerializer.Serialize(level2)); //==> {"Scrore":10} public interface ILevel1 { string Name { get; set; } string City { get; set; } } public interface ILevel2 : ILevel1 { int Scrore { get; set; } } public class FullClass : ILevel2 { public int Scrore { get; set; } public string Name { get; set; } public string City { get; set; } }
内容的提问来源于stack exchange,提问作者btbenjamin
相关产品推荐
相关产品推荐

