【问题标题】:Can I optionally turn off the JsonIgnore attribute at runtime?我可以选择在运行时关闭 JsonIgnore 属性吗?
【发布时间】:2016-05-22 07:43:35
【问题描述】:

我正在使用 Newtonsoft.Json 从一组类中创建一个 JSON 文件。创建的文件非常大,因此我为属性创建了JsonProperty 以减小大小,并为某些数据类型添加了JsonIgnore 和自定义格式。

结果是从 24MB 减少到 1MB,这很棒;但是,我希望选择在运行时生成完整版本或缩减属性版本。

无论如何我可以让序列化程序有选择地使用属性吗?

【问题讨论】:

  • 或许可以展示一些代码,说明到目前为止您是如何设法自定义 JSON.Net 的。

标签: c# .net json.net


【解决方案1】:

是的,这可以使用自定义 ContractResolver 来完成。

你没有展示任何代码,所以我只是举个例子。假设我有一个类Foo,如下所示。我想要序列化输出中的IdName 属性,但我绝对对AlternateNameColor 不感兴趣。我用[JsonIgnore] 标记了那些。我希望出现描述,但有时这会变得很长,所以我使用了自定义 JsonConverter 来限制它的长度。我还想为描述使用较短的属性名称,所以我用[JsonProperty("Desc")] 标记了它。

class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    [JsonIgnore]
    public string AlternateName { get; set; }
    [JsonProperty("Desc")]
    [JsonConverter(typeof(StringTruncatingConverter))]
    public string Description { get; set; }
    [JsonIgnore]
    public string Color { get; set; }
}

当我序列化上述实例时...

Foo foo = new Foo
{
    Id = 1,
    Name = "Thing 1",
    AlternateName = "The First Thing",
    Description = "This is some lengthy text describing Thing 1 which you'll no doubt find very interesting and useful.",
    Color = "Yellow"
};

string json = JsonConvert.SerializeObject(foo, Formatting.Indented);

...我得到这个输出:

{
  "Id": 1,
  "Name": "Thing 1",
  "Desc": "This is some lengthy text describing Thing 1 "
}

现在,假设我有时想获得完整的 JSON 输出,而忽略了我的自定义。我可以使用自定义ContractResolver 以编程方式“取消应用”类中的属性。这是解析器的代码:

class IgnoreJsonAttributesResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
        foreach (var prop in props)
        {
            prop.Ignored = false;   // Ignore [JsonIgnore]
            prop.Converter = null;  // Ignore [JsonConverter]
            prop.PropertyName = prop.UnderlyingName;  // restore original property name
        }
        return props;
    }
}

要使用解析器,我将其添加到 JsonSerializerSettings 并将设置传递给序列化器,如下所示:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new IgnoreJsonAttributesResolver();
settings.Formatting = Formatting.Indented;

string json = JsonConvert.SerializeObject(foo, settings);

输出现在包括被忽略的属性,并且描述不再被截断:

{
  "Id": 1,
  "Name": "Thing 1",
  "AlternateName": "The First Thing",
  "Description": "This is some lengthy text describing Thing 1 which you'll no doubt find very interesting and useful.",
  "Color": "Yellow"
}

完整演示:https://dotnetfiddle.net/WZpeWt

【讨论】:

  • Brill answer Brian,工作就像一个魅力,你知道如何关闭 [JsonProperty("ShortName")] 属性吗?
  • 是的,在解析器的循环中添加prop.PropertyName = prop.UnderlyingName;。这将导致该属性使用其原始名称。
  • @BrianRogers 很好的答案。在我的场景中,我有一个要转换的对象图,对于树中的每种类型(实现特定类型时),我需要根据它们的值包含/排除属性。
  • @Shimmy 如果您有后续问题,您应该ask it as a new question。如果它有助于提供上下文,您可以包括 a link back to this question。评论区不是提问的好地方,因为 cmets 在长度和格式上都有限制;它们不可搜索,也不会出现在问题列表中,这意味着您获得满意答案的可能性要小得多。
  • 我不说谢谢,因为这不符合这里的规定。但如果可能的话,我会多次投票给你的答案! THX... :D
【解决方案2】:

Json 支持我们忽略不想返回的属性。 示例

class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string AlternateName { get; set; }    
}

使用方法:

Foo foo = new Foo
{
    Id = 1,
    Name = "Thing 1",
    AlternateName = null,   
};

string json = JsonConvert.SerializeObject(foo);

【讨论】:

  • 这没有回答所提出的问题。
【解决方案3】:

如果您愿意使用 F#(或只是使用未针对 C# 优化的 API),FSharp.JsonSkippable 库包含一个通用包装器类型,允许您以简单且强类型的方式控制是否包含给定属性序列化时(并确定反序列化时是否包含属性),此外,控制/确定排除可空性。 (完全披露:我是图书馆的作者。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-04
    • 2015-06-19
    • 2010-09-08
    • 1970-01-01
    • 2022-11-11
    • 2018-12-05
    • 2011-05-27
    • 1970-01-01
    相关资源
    最近更新 更多