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

时间:2011-05-03 16:48:28

标签: c# serialization json.net

给出数据模型:

[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; }
}

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

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

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

6 个答案:

答案 0 :(得分:31)

我使用自定义Contract Resolver来限制要序列化的哪些属性。这可能会指出你正确的方向。

e.g。

/// <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;
    }
}

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

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

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

答案 1 :(得分:21)

我有完全相同的问题,并查找如何构建我实际上正在寻找的ContractResolver,并更好地回答这个问题。这只序列化了你想要序列化的Type 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;
    }
}

答案 2 :(得分:3)

遇到类似的问题,这是我提出的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属性可能引用的其他类型的属性。根据您的需要,这可能会或可能不会比当时提供的其他答案有所改进。

答案 3 :(得分:2)

查看answers in this similar thread,特别是IgnorableSerializerContractResolver in my answer和更好的lambda version

用法:

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 };

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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

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