Avi*_*viD 46 .net c# serialization json.net
通过JSON.NET序列化任意数据时,任何null属性都将写入JSON
"propertyName":null
当然,这是正确的.
但是我要求自动将所有空值转换为默认的空值,例如null strings应该变为String.Emptynull,int?s应该变为0null,bool?s应该是false,等等.
NullValueHandling没有帮助,因为我不想Ignore空,但我也不想要Include它们(嗯,新功能?).
所以我转向实施自定义JsonConverter.
虽然实现本身是轻而易举的,但不幸的是,这仍然CanConvert()无法工作 - 永远不会调用具有null值的属性,因此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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在调试器中逐步执行此操作,我注意到这些方法都没有为具有空值的属性调用.
深入研究JSON.NET的源代码,我发现(显然,我没有深入研究)有一个特殊情况检查空值,并且明确地调用.WriteNull().
为了它的价值,我尝试实现自定义JsonTextWriter并覆盖默认.WriteNull()实现...
public class NullJsonWriter : JsonTextWriter
{
...
public override void WriteNull()
{
this.WriteValue(String.Empty);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这不能很好地工作,因为该WriteNull()方法对底层数据类型一无所知.所以可以肯定的是,我可以""为任何null 输出,但这对于例如int,bool等不起作用.
所以,我的问题 - 没有手动转换整个数据结构,是否有任何解决方案或解决方法?
J. *_*mes 26
好吧,我想我已经提出了一个解决方案(我的第一个解决方案根本不对,但我再次在火车上).您需要为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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后我用它测试了它:
class Foo
{
public int? Int { get; set; }
public bool? Boolean { get; set; }
public int? IntField;
}
Run Code Online (Sandbox Code Playgroud)
以下案例:
[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}");
}
}
Run Code Online (Sandbox Code Playgroud)
希望这有点帮助......
编辑 - 更好地识别a Nullable<>类型
编辑 - 添加对字段和属性的支持,还可以在正常情况下DynamicValueProvider进行支持以完成大部分工作,并使用更新的测试
| 归档时间: |
|
| 查看次数: |
43311 次 |
| 最近记录: |