Newtonsoft序列化基类时包含子类属性的原因及解决方法
成因
Json.NET(Newtonsoft.Json)的默认序列化逻辑是运行时读取实例的真实类型反射获取可序列化成员,和你声明变量时用的类型无关。
你将ChildClass实例向上转型为BaseClass,只是限制了C#编译期对该变量的访问权限——编译期只会校验你调用的成员是否属于BaseClass,但堆上存储的实例本身仍然是ChildClass类型。Json.NET序列化时是在运行时直接读取实例的真实类型,自然会扫描到ChildClass定义的所有公开字段,和编译期的类型检查是完全独立的两套逻辑,所以会输出Property2字段。
解决方案
方案1:序列化时显式指定序列化的基准类型
用JsonConvert.SerializeObject的重载,手动传入你要序列化的类型typeof(BaseClass),Json.NET会按指定类型扫描成员,不会读取子类的额外属性:
Console.WriteLine(JsonConvert.SerializeObject(baseInstance, typeof(BaseClass), Formatting.Indented));
这个方案不需要修改原有类定义,适合临时单场景使用。
方案2:为子类不需要序列化的属性加[JsonIgnore]特性
如果确定Property2在任何序列化场景都不需要输出,可以直接给字段加忽略特性:
class ChildClass : BaseClass { [JsonIgnore] public string Property2; }
这个方案会全局生效,不适合需要在部分场景序列化Property2的需求。
方案3:自定义契约解析器批量限制序列化层级
如果有大量基类子类的序列化场景需要统一控制只序列化基类成员,可以自定义契约解析器:
public class BaseTypeContractResolver : DefaultContractResolver { private readonly Type _baseType; public BaseTypeContractResolver(Type baseType) => _baseType = baseType; protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) { return base.CreateProperties(_baseType, memberSerialization); } }
使用时传入序列化配置即可:
var serializeSettings = new JsonSerializerSettings { ContractResolver = new BaseTypeContractResolver(typeof(BaseClass)), Formatting = Formatting.Indented }; Console.WriteLine(JsonConvert.SerializeObject(baseInstance, serializeSettings));
这个方案适合批量统一处理的场景,灵活性更高。
内容的提问来源于stack exchange,提问作者ajax2112
相关产品推荐
相关产品推荐

