我有以下模型结构:
public class A
{
[JsonProperty("id")]
public string Id { get { return "A:ID"; } }
[JsonProperty("CompKey")]
public string CompKey { get; set; }
}
public class B : A
{
[JsonProperty("id")]
public string Id { get { return "B:ID"; } }
[JsonProperty("name")]
public string Name { get; set; }
}
我想序列化类B的实例,但只希望类A的Id属性可见。我创建了一个合同解析程序以传递给Newtonsoft:
public class DatabaseEntryResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance => property.DeclaringType == typeof(A);
return property;
}
}
我以以下方式使用它:
var someObject = new A();
var json = JsonConvert.SerializeObject(someObject, new JsonSerializerSettings
{
ContractResolver = new DatabaseEntryResolver()
});
但是,这两个ID属性都不是在JSON结构中创建的。有人可能会对我的这个问题有所了解吗?
DefaultContractResolver
遇到两个名称相同的属性,它会选择序列化不被忽略的最派生的属性。值得注意的是,此决策是基于静态元数据,例如[JsonIgnore]
的存在或不存在,而不是基于运行时状态,例如从ShouldSerialize
返回。
因此,要使A.Id
在序列化B
的实例时取代B.Id
,必须重写CreateProperty()
,如下所示:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (member.ReflectedType == typeof(B)) // Use (typeof(A).IsAssignableFrom(member.ReflectedType)) if you want this to apply to all subclasses of A
{
// Make A.Id supersede B.Id
if (member.Name == nameof(A.Id) && member.DeclaringType != typeof(A))
property.Ignored = true;
}
return property;
}
此外,如果您真的希望在序列化B
的实例时,类A的Id属性可见,那么您还必须删除或忽略CreateProperties()
:中的所有其他内容
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
if (type == typeof(B)) // Use typeof(A).IsAssignableFrom(type)) if you want to only serialize the Id property of A and all its subclasses
{
// Remove everything except Id. You could also Ignore everything except Id.
properties = properties.Where(p => p.UnderlyingName == nameof(A.Id)).ToList();
}
return properties;
}
注:
Newtonsoft可能不会检查
ShouldSerialize
来确定要绑定到JSON的Id
属性,因为在反序列化过程中无法调用ShouldSerialize
。如果您真的只想为
A
的每个实例或A
的任何子类序列化{ "id": "A:ID" }
,请使用我在代码注释中提到的typeof(A).IsAssignableFrom()
。应该使用
new
修饰符标记B.Id
,以避免出现编译警告。public class B : A { [JsonProperty("id")] public new string Id { get { return "B:ID"; } } // Fixed compilation
有关更多信息,请参阅了解何时使用覆盖和新关键字(C#编程指南(。
在这里演示小提琴;
对于遇到这个问题的人,开发Netwonsoft.JSON的人在这里给出了解释,这样我的新合同解析器如下:
public class DatabaseEntryResolver : DefaultContractResolver
{
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
return base.GetSerializableMembers(objectType).Where(member => member.DeclaringType == typeof(A);
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance => property.DeclaringType == typeof(A);
return property;
}
}
请注意,我仍然决定保留重载的CreateProperty方法,尽管从技术上讲它是不需要的,因为重载的GetSerializableMembers方法已经过滤掉了我需要的属性。我决定这样做只是以防万一,但如果没有它,解决方案仍然有效。