web-dev-qa-db-ja.com

Json nullの代わりに空の文字列を変換します

値を取得できなかった文字列が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空文字列としてnullをデシリアライズする方法?

31
Igor Meszaros

これは動作するはずです:

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);
    }
}
31
L.B

受け入れられた答えは私を正しい方向に向けましたが、それは非常に脆いようです。 I しない Json.NETでそれを行うための完全に機能的なツールがある場合、JsonPropertyオブジェクトのリストを解決し、IValueResolverを自分で実装することを心配したい(これは基本的なリフレクションベースの再実装ではない、あらゆる種類の最適化とコーナーケース処理を組み込むことができます)。

私のソリューションは、最小限のオーバーライドとリゾルバの置換を実行して、変更するabsolutely needの部分のみが実際に変更されるようにします。

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

さて、私のソリューションは非常に単純ですが、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;} = "";
}
17
Uriil

@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
Tony