【问题标题】:Json Convert empty string instead of nullJson 转换空字符串而不是 null
【发布时间】:2014-05-23 13:13:07
【问题描述】:

我正在尝试序列化我的结构,以便没有获得值的字符串获得其默认值“”而不是 null

[JsonProperty(PropertyName = "myProperty", DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string MyProperty{ get; set; }

我在 Json 字符串中的结果:

"myProperty": null,

我想要什么

"myProperty": "",

我还尝试创建一个没有任何效果的转换器,can Convert 和 WriteJson 函数由于某种原因甚至没有触发:

[JsonProperty(PropertyName = "myProperty")]
[JsonConverter(typeof(NullToEmptyStringConverter))]
public string MyProperty{ get; set; }

class NullToEmptyStringConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(object[]);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
            writer.WriteValue("");
    }
}

这对Json.Net How to deserialize null as empty string?没有帮助

【问题讨论】:

  • 已经试过了,还是不行
  • DefaultValue 属性的重点不是属性一个默认值。它只是作为序列化的信号,如果属性在序列化时具有该值,则不需要序列化,因为默认情况下它将获得该值。如果您实际上并没有默认为该属性赋予该值,那么您实际上是在滥用该属性。

标签: c# json null string


【解决方案1】:

这应该可行:

var settings = new JsonSerializerSettings() { ContractResolver= new NullToEmptyStringResolver() };
var str = JsonConvert.SerializeObject(yourObj, settings);

public class NullToEmptyStringResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        return type.GetProperties()
                .Select(p=>{
                    var jp = base.CreateProperty(p, memberSerialization);
                    jp.ValueProvider = new NullToEmptyStringValueProvider(p);
                    return jp;
                }).ToList();
    }
}

public class NullToEmptyStringValueProvider : IValueProvider
{
    PropertyInfo _MemberInfo;
    public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
    {
        _MemberInfo = memberInfo;
    }

    public object GetValue(object target)
    {
        object result =  _MemberInfo.GetValue(target);
        if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
        return result;

    }

    public void SetValue(object target, object value)
    {
        _MemberInfo.SetValue(target, value);
    }
}

【讨论】:

  • 我已经设置了另一个合同解析器。似乎没有办法拥有多个
  • @khillang 如果你想做这么多的改变,请提供另一个答案,不要编辑这个。我把它回滚了。
  • 我遇到了需要多个ContractResolvers 的情况。没有多个解析器的选项,但您可以从其他解析器继承。这是一个很好的例子stackoverflow.com/questions/39612636/… 例如,在应用NullToEmptyStringResolver 之后,所有JSON 响应都有小写的字段名称。从CamelCasePropertyNamesContractResolver 继承它对我来说效果很好。
  • 这个解决方案破坏了我正在序列化的对象中的其他几个项目。考虑在下面使用 Kirill Shlenski 的解决方案
【解决方案2】:

虽然接受的答案为我指明了正确的方向,但它看起来很脆弱。我不想担心解决JsonProperty 对象列表并自己实现IValueResolver,因为在 Json.NET 中有功能完善的工具可用于执行此操作(可能有各种优化)以及基于反射的基本重新实现不会内置的极端情况处理)。

我的解决方案执行最少的覆盖和解析器替换,以确保只有绝对需要更改的部分被实际更改:

public sealed class SubstituteNullWithEmptyStringContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        if (property.PropertyType == typeof(string))
        {
            // Wrap value provider supplied by Json.NET.
            property.ValueProvider = new NullToEmptyStringValueProvider(property.ValueProvider);
        }

        return property;
    }

    sealed class NullToEmptyStringValueProvider : IValueProvider
    {
        private readonly IValueProvider Provider;

        public NullToEmptyStringValueProvider(IValueProvider provider)
        {
            if (provider == null) throw new ArgumentNullException("provider");

            Provider = provider;
        }

        public object GetValue(object target)
        {
            return Provider.GetValue(target) ?? "";
        }

        public void SetValue(object target, object value)
        {
            Provider.SetValue(target, value);
        }
    }
}

【讨论】:

    【解决方案3】:

    好吧,我的解决方案非常简单,但不使用 JSON.NET 功能,只需将后端字段添加到您的属性:

    public class Test
    {
        private string _myProperty = string.Empty;
    
        [JsonProperty(PropertyName = "myProperty")]
        public string MyProperty
        {
            get { return _myProperty; }
            set { _myProperty = value; }
        }
    }
    

    编辑:

    在 c# 6.0 中可以进行属性初始化:

    public class Test
    {
        [JsonProperty(PropertyName = "myProperty")]
        public string MyProperty { get; set;} = "";
    }
    

    【讨论】:

    • 我会避免这样做,因为我有 20 多个属性。但是,如果一切都失败了,我想我将别无选择.. 感谢您的回复!
    • 我刚刚在我正在开发的应用程序中尝试了这个,如果你使用映射器(在我的例子中是 ValueInjecter)设置值,那么这不会按预期工作。
    • 没有什么能阻止你调用 MyProperty = null;因此返回一个空字符串。
    【解决方案4】:

    @Kirill Shlenskiy 的解决方案很棒,但它没有考虑NullValueHandling 属性。

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Remark{ get; set; }
    

    这是一个改进的版本,可以解决这个问题。如果设置了NullValueHandling.Ignore,并且值为null,则在JSON输出中会被跳过。

    public sealed class SubstituteNullWithEmptyStringContractResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);
            if (property.PropertyType == typeof(string))
            {
                // Wrap value provider supplied by Json.NET.
                property.ValueProvider = new NullToEmptyStringValueProvider(property.ValueProvider, property.NullValueHandling);
            }
            return property;
        }
    
        sealed class NullToEmptyStringValueProvider : IValueProvider
        {
            private readonly IValueProvider Provider;
            private readonly NullValueHandling? NullHandling;
    
            public NullToEmptyStringValueProvider(IValueProvider provider, NullValueHandling? nullValueHandling)
            {
                Provider = provider ?? throw new ArgumentNullException("provider");
                NullHandling = nullValueHandling;
            }
    
            public object GetValue(object target)
            {
                if (NullHandling.HasValue 
                    && NullHandling.Value == NullValueHandling.Ignore
                    && Provider.GetValue(target) == null )
                {
                    return null;
                }
                return Provider.GetValue(target) ?? "";
            }
    
            public void SetValue(object target, object value)
            {
                Provider.SetValue(target, value);
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      另一种解决方案(也许更简洁)。您可以创建自己的 JsonConverter 类

      class JsonNullToEmptyStringConverter : JsonConverter
      {
          public override bool CanConvert(Type objectType)
          {
              return true;
          }
      
          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
          {
              return existingValue ?? string.Empty;
          }
      
          public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
          {
              writer.WriteValue(value ?? string.Empty);
          }
      }
      

      写完后,您可以将其作为属性附加到您的财产上:

      [JsonConverter(typeof(JsonNullToEmptyStringConverter))]
      public string CommentType { get; set; }
      

      【讨论】:

        【解决方案6】:

        原来的课不是我的。提前感谢许多像您一样做出贡献的人!

        我添加并解决了 null 问题。

        Public Class JsonBooleanConverter
            Inherits JsonConverter
        
            Public Status As String
            Public ErrorCode As String
            <JsonProperty(NullValueHandling:=NullValueHandling.Ignore)>
            Public ErrorMessage As String
            Public Overrides ReadOnly Property CanWrite As Boolean
                Get
                    Return False
                End Get
            End Property
        
            Public Overrides Sub WriteJson(ByVal writer As JsonWriter, ByVal value As Object, ByVal serializer As JsonSerializer)
                Throw New NotImplementedException()
            End Sub
        
            Public Overrides Function ReadJson(ByVal reader As JsonReader, ByVal objectType As Type, ByVal existingValue As Object, ByVal serializer As JsonSerializer) As Object
        
                If IsNothing(reader.Value) Then
                    Return If(existingValue, String.Empty)
                End If
        
                Dim value = reader.Value.ToString().ToLower().Trim()
        
                If objectType = GetType(Boolean) Then
                    Select Case value
                        Case "true", "yes", "y", "1"
                            Return True
        
                        Case Else
                            Return False
                    End Select
        
                ElseIf objectType = GetType(DateTime) Then
                    Return If(existingValue, String.Empty)
                End If
                Return If(existingValue, String.Empty)
                'Return False
            End Function
        
            Public Overrides Function CanConvert(ByVal objectType As Type) As Boolean
                If objectType = GetType(Boolean) Then
                    Return True
                ElseIf objectType = GetType(DateTime) Then
                    Return True
                End If
        
                Return False
            End Function
        
        End Class
        

        用法:

        Dim listObjs As List(Of YourClass) = JsonConvert.DeserializeObject(Of List(Of YourClass))(responseFromServer, New JsonBooleanConverter())
        

        或者:

        Dim listObjs As YourClass= JsonConvert.DeserializeObject(Of YourClass)(responseFromServer, New JsonBooleanConverter())
        

        【讨论】:

          【解决方案7】:

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

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

          使用 .NET 6 这是解决方案:

          [JsonIgnore(条件 = JsonIgnoreCondition.WhenWritingNull)]

          这里https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-ignore-properties?pivots=dotnet-6-0



          与 Newtonsoft https://www.newtonsoft.com/json/help/html/NullValueHandlingIgnore.htm

          , Formatting.Indented,新的 JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }

          Person person = new Person
          {
             Name = "Nigal Newborn",
             Age = 1
          };
          
              string jsonIncludeNullValues = JsonConvert.SerializeObject(person, Formatting.Indented);
          
          Console.WriteLine(jsonIncludeNullValues);
          // {
          //   "Name": "Nigal Newborn",
          //   "Age": 1,
          //   "Partner": null,
          //   "Salary": null
          // }
          
          string jsonIgnoreNullValues = JsonConvert.SerializeObject(person, 
          Formatting.Indented,  new JsonSerializerSettings
          {
              NullValueHandling = NullValueHandling.Ignore
           } );
          
          Console.WriteLine(jsonIgnoreNullValues);
          // {
          //   "Name": "Nigal Newborn",
          //   "Age": 1
          // }
          

          【讨论】:

            猜你喜欢
            • 2016-10-17
            • 1970-01-01
            • 1970-01-01
            • 2015-09-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-06-10
            • 2020-12-31
            相关资源
            最近更新 更多