如何阻止不可修改类型的成员被Newtonsoft.Json序列化/反序列化
解决方案
方案1:属性标注实现(完全符合需求,对现有代码侵入最小)
你可以通过自定义 JsonConverter 实现,仅需要在用到 RecurrenceInfo 的属性上加一行标注,无需修改全局序列化配置:
- 实现自定义转换器
public class RecurrenceInfoConverter : JsonConverter<RecurrenceInfo> { public override void WriteJson(JsonWriter writer, RecurrenceInfo value, JsonSerializer serializer) { var contract = serializer.ContractResolver.ResolveContract(typeof(RecurrenceInfo)) as JsonObjectContract; if (contract == null) { serializer.Serialize(writer, value); return; } writer.WriteStartObject(); // 遍历所有属性,跳过CustomFields foreach (var prop in contract.Properties.Where(p => p.PropertyName != nameof(RecurrenceInfo.CustomFields))) { if (prop.Ignored || !prop.Readable) continue; var propValue = prop.ValueProvider.GetValue(value); if (propValue == null && serializer.NullValueHandling == NullValueHandling.Ignore) continue; writer.WritePropertyName(prop.PropertyName); serializer.Serialize(writer, propValue, prop.PropertyType); } writer.WriteEndObject(); } public override RecurrenceInfo ReadJson(JsonReader reader, Type objectType, RecurrenceInfo existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObj = JObject.Load(reader); // 反序列化前先移除CustomFields字段 jObj.Remove(nameof(RecurrenceInfo.CustomFields)); var result = hasExistingValue ? existingValue : new RecurrenceInfo(); using var subReader = jObj.CreateReader(); serializer.Populate(subReader, result); return result; } }
- 给属性加标注即可
public class A { [JsonProperty] [JsonConverter(typeof(RecurrenceInfoConverter))] public RecurrenceInfo B { get; set; } }
方案2:多场景复用的轻量配置
如果项目中多处用到 RecurrenceInfo,不想每个属性都加转换器,可以自定义契约解析器,只会影响 RecurrenceInfo 的 CustomFields 字段,不会干扰其他类型的序列化逻辑:
public class SkipCustomFieldsResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); if (property.DeclaringType == typeof(RecurrenceInfo) && property.PropertyName == nameof(RecurrenceInfo.CustomFields)) { property.Ignored = true; } return property; } }
使用时仅需要在对应序列化/反序列化的位置传入配置即可,不需要全局注册:
var settings = new JsonSerializerSettings { ContractResolver = new SkipCustomFieldsResolver() }; // 序列化 var json = JsonConvert.SerializeObject(obj, settings); // 反序列化 var result = JsonConvert.DeserializeObject<A>(json, settings);
方案3:最小改动临时方案
如果只需要快速解决反序列化报错问题,可以加全局错误处理,直接忽略该类异常,代码改动量最小:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Error = (sender, args) => { if (args.ErrorContext.Error is JsonSerializationException ex && ex.Message.Contains("Cannot populate list type DevExpress.XtraScheduler.CustomFieldCollection")) { args.ErrorContext.Handled = true; } } };
内容的提问来源于stack exchange,提问作者Sinatr
相关产品推荐
相关产品推荐

