Подтвердить что ты не робот

Json Преобразует пустую строку вместо null

Я пытаюсь сериализовать свою структуру, чтобы строки, которые не получили значение, получили значение по умолчанию "" вместо null

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

Мой результат в строке Json:

"myProperty": null,

что я хочу

"myProperty": "",

Я также попытался создать конвертер без какого-либо эффекта, функции 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. Как десериализовать null как пустую строку?

4b9b3361

Ответ 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);
    }
}

Ответ 2

Ну, мое решение довольно простое, но не использует функции JSON.NET, просто добавьте backend-поле в ваше свойство:

public class Test
{
    private string _myProperty = string.Empty;

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

Edit:

В свойствах свойства С# 6.0 будет доступно:

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

Ответ 3

Пока принятый ответ указал мне в правильном направлении, он выглядит довольно хрупким. Я не хочу беспокоиться о том, чтобы разрешить список объектов 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);
        }
    }
}