Newtonsoft Json.NET 不序列化[Obsolete]属性。

3
有没有办法配置Json.NET不序列化带有[Obsolete]属性的属性?例如:
public class Foo
{
    public int Id { get; set; }

    [Obsolete]
    public int Age { get; set; }
 }

 var foo = new Foo { Id = 123, Age = 23 };
 var json = JsonConvert.SerializeObject(foo);

在上面的例子中,json 是 {"Id":123,"Age":23}
我想要的是 {"Id":123}

从Making a property deserialize but not serialize with json.net的任何答案是否符合您的需求? - dbc
你不能简单地添加[JsonIgnore]属性吗? - Steve B
@SteveB 很不幸,我无法控制 Foo 类。 - Matt Frear
3个回答

9

是的,您可以使用自定义的ContractResolver来排除已标记为过时的属性。
以下是解析器所需的代码:

public class ExcludeObsoletePropertiesResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);
        if (prop.AttributeProvider.GetAttributes(true).OfType<ObsoleteAttribute>().Any())
        {
            prop.ShouldSerialize = obj => false;
        }
        return prop;
    }
}

然后像这样使用它:
var settings = new JsonSerializerSettings
{
    ContractResolver = new ExcludeObsoletePropertiesResolver()
};
var json = JsonConvert.SerializeObject(foo, settings);

这里有一个工作演示:https://dotnetfiddle.net/gIRCD4


好的。谢谢你提供的代码演示! - Matt Frear
难道重写收集需要序列化成员并在那里过滤成员的方法不是更好吗?protected override List GetSerializableMembers(Type objectType) { var members = base.GetSerializableMembers(objectType); members.RemoveAll(m => m.IsDefined(typeof(ObsoleteAttribute), true)); return members; } - Sindri Jóelsson
@SindriJóelsson 取决于你想做什么。如果你想在序列化时排除成员,但仍然允许它们反序列化(这似乎对于一个 [Obsolete] 属性是可取的),那么你不应该过滤掉成员,而是设置 ShouldSerialize 谓词,就像我的答案中所示。如果你想要双向排除它们,那么过滤它们是一种方法。另一种方法是在属性上设置 Ignored = true - Brian Rogers
@BrianRogers,我发现在发布答案后这一点。 当我为我的用例实施时,访问或设置过时的成员将会抛出异常。 - Sindri Jóelsson

1
您可以按照此处文档所述使用条件序列化:https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm 如果您控制该类并希望针对预先知道的特定属性,则使用第一种机制更容易,提供ShouldSerializeAge()方法。
但最可能的情况是您需要某些通用内容,在这种情况下,您可以创建一个IContractResolver类,使用反射来检查给定属性是否具有Obselete属性。

谢谢你的回答。我无法控制相关的类。 - Matt Frear

0
扩展Brian Rogers的答案:在GetSerializableMembers()方法的覆盖中过滤要排除的成员比在每个MemberInfo上调用的CreateProperty(MemberInfo member, MemberSerialization memberSerialization)更简单/更快,以避免不必要的调用CreateProperty方法,该方法执行大量反射和委托创建。
public class ExcludeObsoletePropertiesResolver : DefaultContractResolver
{
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        var members =  base.GetSerializableMembers(objectType);
        members.RemoveAll(m => m.IsDefined(typeof(ObsoleteAttribute), true));
        return members;
    }
}

使用方法:

var settings = new JsonSerializerSettings
{
    ContractResolver = new ExcludeObsoletePropertiesResolver()
};
var json = JsonConvert.SerializeObject(foo, settings);

哦,这看起来很漂亮、干净。 - Matt Frear

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接