【问题标题】:How to ignore a property in class if null, using json.net如果为空,如何使用 json.net 忽略类中的属性
【发布时间】:2011-09-24 08:57:22
【问题描述】:

我正在使用Json.NET 将一个类序列化为 JSON。

我有这样的课程:

class Test1
{
    [JsonProperty("id")]
    public string ID { get; set; }
    [JsonProperty("label")]
    public string Label { get; set; }
    [JsonProperty("url")]
    public string URL { get; set; }
    [JsonProperty("item")]
    public List<Test2> Test2List { get; set; }
}

仅当Test2Listnull 时,我才想将JsonIgnore() 属性添加到Test2List 属性。如果它不为空,那么我想将它包含在我的 json 中。

【问题讨论】:

    标签: c# json.net


    【解决方案1】:

    使用JsonProperty 属性的替代解决方案:

    [JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
    // or
    [JsonProperty("property_name", NullValueHandling=NullValueHandling.Ignore)]
    
    // or for all properties in a class
    [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
    

    this online doc 所示。

    【讨论】:

    • 接受的答案更好,因为它不会用 Json.net 属性污染你的类。
    • @Sergey 这取决于您的用例。如果您只想将它​​用于特定属性(如问题中所述),那么这是正确的答案。如果你想要一个全局的答案,你应该在 JsonSerializer 中设置属性。
    • @Destek 您需要使引用类型字段可以为空,然后它们将不会使用属性或设置进行序列化。
    • 为避免使用许多属性“污染”您的类,您还可以在 [JsonObject] 上分配处理规则,但请注意属性名称不同。 [编辑答案]
    • 嗯,无法使 [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] 工作:找不到类型或命名空间名称“ItemNullValueHandling”。我确实使用 Newtonsoft.Json.Serialization 添加了; ...
    【解决方案2】:

    按照 James Newton King 的说法:如果您自己创建序列化程序而不是使用 JavaScriptConvert,则可以将 NullValueHandling property 设置为忽略。

    这是一个示例:

    JsonSerializer _jsonWriter = new JsonSerializer {
                                     NullValueHandling = NullValueHandling.Ignore
                                 };
    

    或者,正如@amit 所建议的那样

    JsonConvert.SerializeObject(myObject, 
                                Newtonsoft.Json.Formatting.None, 
                                new JsonSerializerSettings { 
                                    NullValueHandling = NullValueHandling.Ignore
                                });
    

    【讨论】:

    • 这有效:JsonConvert.SerializeObject(myObject, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore});
    • 一件重要的事情 - 它只适用于具体的类(Person、Account 等)。当我用字典尝试这个时,它不起作用
    • 我和@chester89 有同样的问题。对于 ExpandoObject,空值不会被忽略。这似乎是一个错误(使用 json.net 9.0.1)
    • 写答案的时候,JSON.Net 甚至不支持动态对象。 :) 目前,您可以使用自定义转换器进行出价。
    • 无法让它工作...我得到空括号 {"propName":{}}
    【解决方案3】:

    JSON.NET 也尊重 DataMemberAttribute 上的 the EmitDefaultValue property,以防您不想将 Newtonsoft 特定的属性添加到您的模型:

    [DataMember(Name="property_name", EmitDefaultValue=false)]
    

    【讨论】:

    • 这很有帮助!我正在设计一个自定义的异常类,我不想在其中添加 Json.net 的东西。谢谢!
    • 这在 .Net Core 中不起作用。推荐@sirthomas 答案:使用 [JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
    • 在 .Net Core 中使用 Newtonsoft.Json 10.0.2 对我来说效果很好。
    • 这在没有 Newtonsoft.Json 的 asp.net core 3.1 中不起作用
    • @LeiChi 这个问题是关于 Newtonsoft.Json 的;如果您使用的是本机 System.Text.Json,则需要单独提出一个问题。
    【解决方案4】:

    你可以写:[JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

    它还负责不使用默认值(不仅是 null)序列化属性。例如,它对枚举很有用。

    【讨论】:

    • 这和sirthomas的回答一模一样,为什么要加呢?
    • 供您参考,DefaultValueHandling 和 NullValueHandling 之间存在区别...
    • 你能在你的回答中解释一下吗?乍一看,它看起来是一样的,现在你已经提到了,它没有说明这与其他答案有何不同/它如何赞美它。
    • 虽然接受的答案在某些情况下可能有用,但并不总是可以使用它。这正是医生所要求的。
    • 我想这就是我想要的。对某些属性的特定处理,而不是全部。
    【解决方案5】:

    您可以这样做以忽略您正在序列化的对象中的所有空值,并且任何空属性都不会出现在 JSON 中

    JsonSerializerSettings settings = new JsonSerializerSettings();
    settings.NullValueHandling = NullValueHandling.Ignore;
    var myJson = JsonConvert.SerializeObject(myObject, settings);
    

    【讨论】:

      【解决方案6】:

      从他们网站上的这个链接可以看出 (http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size. aspx) 我支持使用 [Default()] 来指定默认值

      取自链接

         public class Invoice
      {
        public string Company { get; set; }
        public decimal Amount { get; set; }
      
        // false is default value of bool
        public bool Paid { get; set; }
        // null is default value of nullable
        public DateTime? PaidDate { get; set; }
      
        // customize default values
        [DefaultValue(30)]
        public int FollowUpDays { get; set; }
        [DefaultValue("")]
        public string FollowUpEmailAddress { get; set; }
      }
      
      
      Invoice invoice = new Invoice
      {
        Company = "Acme Ltd.",
        Amount = 50.0m,
        Paid = false,
        FollowUpDays = 30,
        FollowUpEmailAddress = string.Empty,
        PaidDate = null
      };
      
      string included = JsonConvert.SerializeObject(invoice,
        Formatting.Indented,
        new JsonSerializerSettings { });
      
      // {
      //   "Company": "Acme Ltd.",
      //   "Amount": 50.0,
      //   "Paid": false,
      //   "PaidDate": null,
      //   "FollowUpDays": 30,
      //   "FollowUpEmailAddress": ""
      // }
      
      string ignored = JsonConvert.SerializeObject(invoice,
        Formatting.Indented,
        new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
      
      // {
      //   "Company": "Acme Ltd.",
      //   "Amount": 50.0
      // }
      

      【讨论】:

        【解决方案7】:

        在 .Net Core 中,现在这要容易得多。在你的 startup.cs 中添加 json 选项,你可以在那里配置设置。

        
        public void ConfigureServices(IServiceCollection services)
        
        ....
        
        services.AddMvc().AddJsonOptions(options =>
        {
           options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;               
        });
        
        

        【讨论】:

          【解决方案8】:

          使用 Json.NET

           public class Movie
           {
                      public string Name { get; set; }
                      public string Description { get; set; }
                      public string Classification { get; set; }
                      public string Studio { get; set; }
                      public DateTime? ReleaseDate { get; set; }
                      public List<string> ReleaseCountries { get; set; }
           }
          
           Movie movie = new Movie();
           movie.Name = "Bad Boys III";
           movie.Description = "It's no Bad Boys";
          
           string ignored = JsonConvert.SerializeObject(movie,
                      Formatting.Indented,
                      new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
          

          结果将是:

          {
             "Name": "Bad Boys III",
             "Description": "It's no Bad Boys"
           }
          

          【讨论】:

            【解决方案9】:

            改编自@Mrchief's / @amit's answer,但适用于使用 VB 的人

             Dim JSONOut As String = JsonConvert.SerializeObject(
                       myContainerObject, 
                       New JsonSerializerSettings With {
                             .NullValueHandling = NullValueHandling.Ignore
                           }
              )
            

            见: "Object Initializers: Named and Anonymous Types (Visual Basic)"

            https://msdn.microsoft.com/en-us/library/bb385125.aspx

            【讨论】:

              【解决方案10】:

              在我的情况下,使用 .NET 6 这是解决方案:

              [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
              

              更多信息here.

              【讨论】:

                【解决方案11】:

                使用 System.Text.Json 和 .NET Core 3.0 这对我有用:

                var jsonSerializerOptions = new JsonSerializerOptions()
                {
                    IgnoreNullValues = true
                };
                var myJson = JsonSerializer.Serialize(myObject, jsonSerializerOptions );
                

                【讨论】:

                  【解决方案12】:

                  要稍微解释一下 GlennG 非常有用的答案(将语法从 C# 转换为 VB.Net 并不总是“显而易见的”),您还可以装饰单个类属性来管理如何处理空值。如果您这样做,请不要使用 GlennG 建议中的全局 JsonSerializerSettings,否则它将覆盖各个装饰。如果您希望空项目出现在 JSON 中,这会派上用场,这样消费者就不必进行任何特殊处理。例如,如果消费者需要知道一组可选项目通常是可用的,但当前是空的...... 属性声明中的装饰是这样的:

                  <JsonPropertyAttribute("MyProperty", DefaultValueHandling:=NullValueHandling.Include)> Public Property MyProperty As New List(of String)
                  

                  对于您根本不希望出现在 JSON 中的那些属性,将 :=NullValueHandling.Include 更改为 :=NullValueHandling.Ignore。 顺便说一句 - 我发现您可以很好地装饰 XML 和 JSON 序列化的属性(只需将它们放在一起)。这使我可以选择在 dotnet 中调用 XML 序列化程序或随意调用 NewtonSoft 序列化程序 - 两者并排工作,我的客户可以选择使用 XML 或 JSON。这就像门把手上的鼻涕一样光滑,因为我有客户需要两者!

                  【讨论】:

                    【解决方案13】:

                    这是一个类似的选项,但提供了另一种选择:

                    public class DefaultJsonSerializer : JsonSerializerSettings
                    {
                        public DefaultJsonSerializer()
                        {
                            NullValueHandling = NullValueHandling.Ignore;
                        }
                    }
                    

                    然后,我这样使用它:

                    JsonConvert.SerializeObject(postObj, new DefaultJsonSerializer());
                    

                    这里的区别在于:

                    • 通过实例化和配置JsonSerializerSettings 的每个使用位置来减少重复代码。
                    • 节省了配置要序列化的每个对象的每个属性的时间。
                    • 仍然为其他开发人员提供了序列化选项的灵活性,而不是在可重用对象上明确指定属性。
                    • 我的用例是代码是第三方库,我不想将序列化选项强加给想要重用我的类的开发人员。
                    • 潜在的缺点是它是其他开发人员需要了解的另一个对象,或者如果您的应用程序很小并且这种方法对于单个序列化无关紧要。

                    【讨论】:

                      【解决方案14】:

                      这并不能完全回答原始问题,但可能会根据用例证明有用。 (而且由于我是在搜索后来到这里的,它可能对其他人有用。)

                      根据我最近的经验,我正在使用 PATCH api。如果指定了一个属性但没有给出值(null/undefined,因为它是 js),那么该属性和值将从正在修补的对象中删除。因此,我一直在寻找一种方法来选择性地构建一个可以以这样的方式序列化的对象。

                      我记得看到过 ExpandoObject,但直到今天才真正找到它的用例。这允许您动态构建一个对象,因此您不会有空属性,除非您想要它们。

                      Here 是一个工作小提琴,代码如下。

                      结果:

                      Standard class serialization
                          noName: {"Name":null,"Company":"Acme"}
                          noCompany: {"Name":"Fred Foo","Company":null}
                          defaultEmpty: {"Name":null,"Company":null}
                      ExpandoObject serialization
                          noName: {"Company":"Acme"}
                          noCompany: {"name":"Fred Foo"}
                          defaultEmpty: {}
                      

                      代码:

                      using Newtonsoft.Json;
                      using System;
                      using System.Dynamic;
                                          
                      public class Program
                      {
                          public static void Main()
                          {
                              SampleObject noName = new SampleObject() { Company = "Acme" };
                              SampleObject noCompany = new SampleObject() { Name = "Fred Foo" };
                              SampleObject defaultEmpty = new SampleObject();
                              
                              
                              Console.WriteLine("Standard class serialization");
                              Console.WriteLine($"    noName: { JsonConvert.SerializeObject(noName) }");
                              Console.WriteLine($"    noCompany: { JsonConvert.SerializeObject(noCompany) }");
                              Console.WriteLine($"    defaultEmpty: { JsonConvert.SerializeObject(defaultEmpty) }");
                              
                              
                              Console.WriteLine("ExpandoObject serialization");
                              Console.WriteLine($"    noName: { JsonConvert.SerializeObject(noName.CreateDynamicForPatch()) }");
                              Console.WriteLine($"    noCompany: { JsonConvert.SerializeObject(noCompany.CreateDynamicForPatch()) }");
                              Console.WriteLine($"    defaultEmpty: { JsonConvert.SerializeObject(defaultEmpty.CreateDynamicForPatch()) }");
                          }
                      }
                      
                      public class SampleObject {
                          public string Name { get; set; }
                          public string Company { get; set; }
                          
                          public object CreateDynamicForPatch()
                          {
                              dynamic x = new ExpandoObject();
                              
                              if (!string.IsNullOrWhiteSpace(Name))
                              {
                                  x.name = Name;
                              }
                              
                              if (!string.IsNullOrEmpty(Company))
                              {
                                  x.Company = Company;
                              }
                              
                              return x;
                          }
                      }
                      

                      【讨论】:

                        【解决方案15】:

                        或者只是这样设置。

                        services.AddMvc().AddJsonOptions(options =>
                          options.JsonSerializerOptions.IgnoreNullValues = true;
                        });
                        

                        【讨论】:

                          【解决方案16】:
                          var settings = new JsonSerializerSettings();
                          settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                          settings.NullValueHandling = NullValueHandling.Ignore;
                          //you can add multiple settings and then use it
                          var bodyAsJson = JsonConvert.SerializeObject(body, Formatting.Indented, settings);
                          

                          【讨论】:

                          • settings.NullValueHandling = NullValueHandling.Ignore 在其他答案中被推荐。不清楚,你的答案有什么新变化
                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2018-12-11
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2013-04-16
                          • 2017-08-08
                          相关资源
                          最近更新 更多