如何强制序列化带[JsonIgnore]属性的字段?仅反序列化时忽略
当然可以实现这种序列化可见、反序列化忽略的只读Json属性!下面针对两种主流的.NET Json序列化库,给你具体的实现方案:
使用 Newtonsoft.Json(Json.NET)的方案
如果你用的是老牌的Newtonsoft.Json,有两种常用方式:
方式1:私有Setter + [JsonProperty]标记
如果你的业务场景允许把x的setter设为私有,这是最简单的方案:
public class Cake { // 序列化时会读取getter,反序列化时因setter私有无法赋值 [JsonProperty] public int x { get; private set; } }
这样Json.NET会正常序列化x的值,但反序列化时会自动忽略传入的x字段,完全不会修改属性值。
方式2:自定义ContractResolver(保留公有Setter)
如果必须保留x的公有setter,可以通过自定义ContractResolver来精准控制序列化/反序列化行为:
public class ReadOnlyJsonPropertyResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); // 针对名为x的属性,设置为可序列化、不可反序列化 if (member.Name == nameof(Cake.x)) { property.ShouldDeserialize = _ => false; property.ShouldSerialize = _ => true; } return property; } }
使用时在序列化配置里指定这个Resolver:
var settings = new JsonSerializerSettings { ContractResolver = new ReadOnlyJsonPropertyResolver() }; // 序列化 var json = JsonConvert.SerializeObject(cake, settings); // 反序列化 var deserializedCake = JsonConvert.DeserializeObject<Cake>(json, settings);
使用 System.Text.Json 的方案
如果你用的是.NET Core/.NET 5+自带的System.Text.Json,同样有两种方案:
方式1:私有Setter(无需额外标记)
System.Text.Json默认会序列化带有公有getter的属性,不管setter是否私有;而反序列化时只会处理公有setter。所以直接把setter设为私有即可:
public class Cake { // 序列化输出x,反序列化忽略传入的x public int x { get; private set; } }
如果需要在类内部修改x的值,私有setter完全够用。
方式2:自定义TypeInfoResolver(保留公有Setter)
如果必须保留公有setter,可以通过自定义DefaultJsonTypeInfoResolver来控制:
public class ReadOnlyJsonTypeInfoResolver : DefaultJsonTypeInfoResolver { public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { var typeInfo = base.GetTypeInfo(type, options); if (type == typeof(Cake)) { var property = typeInfo.Properties.FirstOrDefault(p => p.Name == nameof(Cake.x)); if (property != null) { // 禁用反序列化 property.IsReadOnly = true; } } return typeInfo; } }
使用时配置到JsonSerializerOptions中:
var options = new JsonSerializerOptions { TypeInfoResolver = new ReadOnlyJsonTypeInfoResolver() }; // 序列化 var json = JsonSerializer.Serialize(cake, options); // 反序列化 var deserializedCake = JsonSerializer.Deserialize<Cake>(json, options);
另外,如果你想通过自定义特性来实现类似[ReadOnlyJsonIgnore]的效果(更优雅的标记),也可以基于上面的Resolver/ContractResolver扩展,扫描自定义特性来批量处理属性,这样就不用硬编码属性名了。
内容的提问来源于stack exchange,提问作者Konrad
相关产品推荐
相关产品推荐

