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

C# 在基类上下文中使用JSON.net时,如何防止派生类的属性序列化?,c#,serialization,json.net,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 C

给定一个数据模型:

[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; }
}
[DataContract]
公共类父类
{
[数据成员]
公共IEnumerable子项{get;set;}
}
[数据合同]
公营儿童
{
[数据成员]
公共字符串Id{get;set;}
}
[数据合同]
公共类ChildDetail:ChildId
{
[数据成员]
公共字符串名称{get;set;}
}
出于实现方便的原因,
Parent
上的
ChildId
对象有时实际上是
ChildDetail
对象。当我使用JSON.net序列化
Parent
时,它们将与所有
ChildDetail
属性一起写出

是否有任何方法可以指示JSON.net(或任何其他JSON序列化程序,我对项目的了解还不够深入,无法提交给一个)在序列化为基类时忽略派生类属性


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

我没有特别使用JSON.Net,因此这对您没有帮助。如果JSON.Net源于.Net序列化系统,那么您应该能够将[NonSerialized]属性添加到您现在希望在基类中序列化的属性中。在基类上调用serialize方法时,序列化应跳过这些元素。

我使用自定义来限制要序列化的属性。这可能会为您指明正确的方向

e、 g

//
///默认情况下,json.net序列化类的所有属性
///此类将告诉json.net仅序列化匹配的属性
///通过querystring传递给criteria对象的有效列的列表
/// 
公共类CriteriaContractResolver:DefaultContractResolver
{
财产清单;
公共CriteriaContractResolver(列表属性)
{
_属性=属性
}
受保护的重写IList CreateProperties(
JSONObject(合同)
{
IList filtered=新列表();
foreach(base.CreateProperties(合同)中的JsonProperty p)
if(_properties.Contains(p.PropertyName))
过滤。添加(p);
返回过滤;
}
}
在override IList函数中,您可以使用反射来填充仅包含父属性的列表

契约解析器应用于json.net序列化程序。此示例来自asp.net mvc应用程序

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

我遇到了完全相同的问题,并查找了如何构建我实际寻找的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;
    }
}
公共类类型仅限合同冲突解决程序:DefaultContractResolver
{
受保护的重写JsonProperty CreateProperty(MemberInfo成员、MemberSerialization MemberSerialization)
{
JsonProperty属性=base.CreateProperty(成员,成员序列化);
property.ShouldSerialize=instance=>property.DeclaringType==typeof(T);
归还财产;
}
}
查看,尤其是

用法:

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

遇到类似问题后,我想到了一个
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
        );
}
公共类StrictTypeContractResolver:DefaultContractResolver
{
私有只读类型_targetType;
public StrictTypeContractResolver(类型targetType)=>\u targetType=targetType;
受保护的重写IList CreateProperties(类型类型,MemberSerialization MemberSerialization)
=>base.CreateProperties
(
_targetType.IsAssignableFrom(类型)?\u targetType:type,
成员序列化
);
}

它只切断
targetType
的后代的属性,而不影响其基类或
targetType
属性可能引用的其他类型的属性。这取决于您的需要,可能是,也可能不是对当时这里提供的其他答案的改进。

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

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

与我想要的稍有不同,就是所有的基类属性都是生成的,而派生类属性都不是。我不想将
[nonserialized]
添加到派生类属性中,因为有时我确实希望派生类按原样序列化,而不是在基类上下文中使用它。这些链接可能会有所帮助。似乎您必须执行自定义序列化@Bueller如果您继承的类是无法修改的本机类,那么这对您没有帮助。这正是我想要的。基于URI中传递的字段的部分响应。谢谢[我想知道为什么这不是一个内置的契约解析程序]您有IRestCriteria类的例子吗?那是从哪里来的?迈卡-我不应该只是剪和贴。此后,我将该类更改为包含属性名称列表。我认为您不应该调用base.CreateProperties,因为您没有调用您编写的新重写方法(仅接受一个参数),因此,您必须传递2个参数,而不仅仅是契约。这就是我所需要的-除了如何为某些类类型设置此行为,或者为不同的类型包含不同的属性集?这正是我所寻找的-我有一个基类,其中包含一些我不想成为exp的属性
Derived d = new Derived();           
string jsonStringD = JsonConvert.SerializeObject(d);
Base b = new Base();
JsonConvert.PopulateObject(jsonStringD, b);
string jsonStringB = JsonConvert.SerializeObject(b);