给定一个数据模型:
[DataContract]
public class Parent
{
[DataMember]
public IEnumerable<ChildId> 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
上的ChildId
对象实际上是ChildDetail
对象。当我使用JSON.net序列化Parent
时,它们与所有ChildDetail
属性一起被写出来。
是否有任何方法可以指示JSON.net(或任何其他JSON序列化器,我没有足够深入到项目中来提交一个)在序列化为基类时忽略派生类属性?
编辑:重要的是,当我序列化派生类直接,我能够产生所有的属性。我只想抑制Parent
对象中的多态性。
我使用自定义契约解析器来限制要序列化的属性。这可能会给你指明正确的方向。
。
/// <summary>
/// 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
/// </summary>
public class CriteriaContractResolver<T> : DefaultContractResolver
{
List<string> _properties;
public CriteriaContractResolver(List<string> properties)
{
_properties = properties
}
protected override IList<JsonProperty> CreateProperties(
JsonObjectContract contract)
{
IList<JsonProperty> filtered = new List<JsonProperty>();
foreach (JsonProperty p in base.CreateProperties(contract))
if(_properties.Contains(p.PropertyName))
filtered.Add(p);
return filtered;
}
}
在override IList函数中,您可以使用反射来仅使用父属性填充列表。
契约解析器应用于json.net序列化器。这个例子来自一个asp.net mvc应用。
JsonNetResult result = new JsonNetResult();
result.Formatting = Formatting.Indented;
result.SerializerSettings.ContractResolver =
new CriteriaContractResolver<T>(Criteria);
我有完全相同的问题,并查找如何构建我实际上正在寻找的ContractResolver和更好地回答这个问题。这只序列化您真正想要序列化的类型T的属性,但是通过这个示例,您也可以轻松地构建类似的方法:
public class TypeOnlyContractResolver<T> : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance => property.DeclaringType == typeof (T);
return property;
}
}
遇到了类似的问题,这是我想到的ContractResolver
:
public class StrictTypeContractResolver : DefaultContractResolver
{
private readonly Type _targetType;
public StrictTypeContractResolver( Type targetType ) => _targetType = targetType;
protected override IList<JsonProperty> CreateProperties( Type type, MemberSerialization memberSerialization )
=> base.CreateProperties
(
_targetType.IsAssignableFrom( type ) ? _targetType : type,
memberSerialization
);
}
它只切断targetType
的后代的属性,不影响其基类的属性或targetType
的属性可能引用的其他类型的属性。这取决于你的需要,可能比当时提供的其他答案有所改进,也可能没有。
查看这个类似线程中的答案,特别是我的答案中的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]属性添加到你现在希望在基类中序列化的属性中。当调用基类上的序列化方法时,序列化应该跳过这些元素。
还没有比较性能影响,但这也是一个有效的解决方案,并且也适用于嵌套/引用对象。
Derived d = new Derived();
string jsonStringD = JsonConvert.SerializeObject(d);
Base b = new Base();
JsonConvert.PopulateObject(jsonStringD, b);
string jsonStringB = JsonConvert.SerializeObject(b);