![](/img/trans.png)
[英]Serializing with Json.NET: how to require a property not being null?
[英]Serializing null in JSON.NET
通過JSON.NET序列化任意數據時,任何為null的屬性都將按以下方式寫入JSON:
“ propertyName”:null
當然,這是正確的。
但是我有一個要求自動將所有null轉換為默認的空值,例如null string
應該變成String.Empty
,null int?
s應該變為0
, bool?
值無效bool?
s應該為false
,依此類推。
NullValueHandling
沒有幫助,因為我不想Ignore
null,但是我也不想Include
它們(嗯,新功能?)。
因此,我轉向實現自定義JsonConverter
。
雖然實現本身很CanConvert()
,但是不幸的是,這種方法仍然沒有用-從來沒有為具有null值的屬性調用WriteJson()
,因此也沒有調用WriteJson()
。 顯然,沒有自定義管道,空值會自動直接直接序列化為null
。
例如,下面是空字符串的自定義轉換器的示例:
public class StringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(string).IsAssignableFrom(objectType);
}
...
public override void WriteJson(JsonWriter writer,
object value,
JsonSerializer serializer)
{
string strValue = value as string;
if (strValue == null)
{
writer.WriteValue(String.Empty);
}
else
{
writer.WriteValue(strValue);
}
}
}
在調試器中逐步進行此操作時,我注意到,對於具有空值的屬性,都不會調用這兩種方法。
深入研究JSON.NET的源代碼,我發現(顯然,我沒有深入探討)有一種特殊情況,它檢查null,並顯式調用.WriteNull()
。
對於它的價值,我確實嘗試實現了自定義JsonTextWriter
並覆蓋了默認的.WriteNull()
實現...
public class NullJsonWriter : JsonTextWriter
{
...
public override void WriteNull()
{
this.WriteValue(String.Empty);
}
}
但是,這不能很好地工作,因為WriteNull()
方法對基礎數據類型一無所知。 因此,可以肯定,我可以為任何null輸出""
,但是對於int,bool等來說效果不佳。
因此,我的問題-除了手動轉換整個數據結構外,是否有解決方案或解決方法?
好的,我想我想出了一個解決方案(我的第一個解決方案根本不對,但隨后我又在火車上)。 您需要為Nullable類型創建一個特殊的合同解析器和一個自定義的ValueProvider。 考慮一下:
public class NullableValueProvider : IValueProvider
{
private readonly object _defaultValue;
private readonly IValueProvider _underlyingValueProvider;
public NullableValueProvider(MemberInfo memberInfo, Type underlyingType)
{
_underlyingValueProvider = new DynamicValueProvider(memberInfo);
_defaultValue = Activator.CreateInstance(underlyingType);
}
public void SetValue(object target, object value)
{
_underlyingValueProvider.SetValue(target, value);
}
public object GetValue(object target)
{
return _underlyingValueProvider.GetValue(target) ?? _defaultValue;
}
}
public class SpecialContractResolver : DefaultContractResolver
{
protected override IValueProvider CreateMemberValueProvider(MemberInfo member)
{
if(member.MemberType == MemberTypes.Property)
{
var pi = (PropertyInfo) member;
if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof (Nullable<>))
{
return new NullableValueProvider(member, pi.PropertyType.GetGenericArguments().First());
}
}
else if(member.MemberType == MemberTypes.Field)
{
var fi = (FieldInfo) member;
if(fi.FieldType.IsGenericType && fi.FieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
return new NullableValueProvider(member, fi.FieldType.GetGenericArguments().First());
}
return base.CreateMemberValueProvider(member);
}
}
然后我使用以下方法進行了測試:
class Foo
{
public int? Int { get; set; }
public bool? Boolean { get; set; }
public int? IntField;
}
和以下情況:
[TestFixture]
public class Tests
{
[Test]
public void Test()
{
var foo = new Foo();
var settings = new JsonSerializerSettings { ContractResolver = new SpecialContractResolver() };
Assert.AreEqual(
JsonConvert.SerializeObject(foo, Formatting.None, settings),
"{\"IntField\":0,\"Int\":0,\"Boolean\":false}");
}
}
希望這會有所幫助...
編輯–更好地識別Nullable<>
類型
編輯–新增了對字段和屬性的支持,並在常規DynamicValueProvider
上附帶了更新的測試,以完成大部分工作
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.