Json转换空字符串而不是null

时间:2014-05-23 13:13:08

标签: c# json null string

我试图序列化我的结构,以便没有获得值的字符串获得默认值""而不是null

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

我在Json字符串中的结果:

"myProperty": null,

我想要什么

"myProperty": "",

我也尝试过创建一个没有任何效果的转换器,因为某些原因,转换和写入JJ函数甚至不会被触发:

[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?

6 个答案:

答案 0 :(得分:31)

这应该有效:

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);
    }
}

答案 1 :(得分:19)

虽然接受的答案指出了我正确的方向,但它看起来很脆弱。我想要担心解决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);
        }
    }
}

答案 2 :(得分:17)

嗯,我的解决方案非常简单,但不使用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;} = "";
}

答案 3 :(得分: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);
        }
    }
}

答案 4 :(得分:1)

原始班级不是我的。在此先感谢像您这样的许多贡献者!

我添加并解决了空问题。

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())

答案 5 :(得分:0)

另一种解决方案(也许更清洁)。您可以创建自己的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; }