正在序列化具有相同名称的属性



我有以下模型结构:

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结构中创建的。有人可能会对我的这个问题有所了解吗?

Json.NET永远不会序列化具有相同名称的两个属性。如果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方法已经过滤掉了我需要的属性。我决定这样做只是以防万一,但如果没有它,解决方案仍然有效。

相关内容

  • 没有找到相关文章

最新更新