使用JSON.net,在基类上下文中使用时,如何防止派生类的属性序列化?

给定一个数据模型:

[DataContract] public class Parent { [DataMember] public IEnumerable Children { get; set; } } [DataContract] public class ChildId { [DataMember] public string Id { get; set; } } [DataContract] public class ChildDetail : ChildId { [DataMember] public string Name { get; set; } } 

出于实现方便的原因,有时Parent上的ChildDetail对象实际上是ChildDetail对象。 当我使用JSON.net序列化Parent ,它们将被写出所有ChildDetail属性。

是否有任何方法可以指示JSON.net(或任何其他JSON序列化程序,我还不能提交到项目中),在序列化为基类时忽略派生类属性?

编辑:重要的是,当我直接序列化派生类时,我能够生成所有属性。 我只想抑制Parent对象中的多态性。

我使用自定义合约解析器来限制我的哪些属性要序列化。 这可能会指向正确的方向。

例如

 ///  /// json.net serializes ALL properties of a class by default /// this class will tell json.net to only serialize properties if they MATCH /// the list of valid columns passed through the querystring to criteria object ///  public class CriteriaContractResolver : DefaultContractResolver { List _properties; public CriteriaContractResolver(List properties) { _properties = properties } protected override IList CreateProperties( JsonObjectContract contract) { IList filtered = new List(); foreach (JsonProperty p in base.CreateProperties(contract)) if(_properties.Contains(p.PropertyName)) filtered.Add(p); return filtered; } } 

在覆盖IList函数中,您可以使用reflection来填充列表,可能只包含父属性。

合同解析程序适用于您的json.net序列化程序。 这个例子来自asp.net mvc应用程序。

 JsonNetResult result = new JsonNetResult(); result.Formatting = Formatting.Indented; result.SerializerSettings.ContractResolver = new CriteriaContractResolver(Criteria); 

我有完全相同的问题,并查找如何构建我实际上正在寻找的ContractResolver,并更好地回答这个问题。 这只序列化了你想要序列化的Type T的属性,但是通过这个例子,你也可以轻松地构建类似的方法:

 public class TypeOnlyContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty property = base.CreateProperty(member, memberSerialization); property.ShouldSerialize = instance => property.DeclaringType == typeof (T); return property; } } 

看看这个类似线程中的答案 ,特别是我的答案中的IgnorableSerializerContractResolver和更好的lambda版本

用法:

 var jsonResolver = new IgnorableSerializerContractResolver(); // ignore single property jsonResolver.Ignore(typeof(Company), "WebSites"); // ignore single datatype jsonResolver.Ignore(typeof(System.Data.Objects.DataClasses.EntityObject)); var jsonSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver }; 

我没有特别使用JSON.Net所以不积极,这将对你有所帮助。 如果JSON.Net从.Net序列化系统派生自己,那么您应该能够将[NonSerialized]属性添加到您现在希望在基类中序列化的属性中。 在基类上调用serialize方法时,序列化应该跳过这些元素。

遇到类似的问题,这是我提出的ContractResolver

 public class StrictTypeContractResolver : DefaultContractResolver { private readonly Type _targetType; public StrictTypeContractResolver( Type targetType ) => _targetType = targetType; protected override IList CreateProperties( Type type, MemberSerialization memberSerialization ) => base.CreateProperties ( _targetType.IsAssignableFrom( type ) ? _targetType : type, memberSerialization ); } 

它只会截断targetType的后代的属性,而不会影响其基类或targetType属性可能引用的其他类型的属性。 根据您的需要,这可能会或可能不会比当时提供的其他答案有所改进。

没有比较性能影响,但这也是一个有效的解决方案,并且也适用于嵌套/引用的对象。

 Derived d = new Derived(); string jsonStringD = JsonConvert.SerializeObject(d); Base b = new Base(); JsonConvert.PopulateObject(jsonStringD, b); string jsonStringB = JsonConvert.SerializeObject(b);