gpt4 book ai didi

c# - 在 JSON.NET 中序列化 null

转载 作者:IT王子 更新时间:2023-10-29 03:52:43 25 4
gpt4 key购买 nike

当通过 JSON.NET 序列化任意数据时,任何为 null 的属性都将作为

写入 JSON

"propertyName" : null

当然,这是正确的。

但是我需要自动将所有空值转换为默认的空值,例如null string应该变成String.Empty,null int?应该变成0,null bool ?s 应该是 false,等等。

NullValueHandling 没有帮助,因为我不想Ignore 空值,但我也不想包含它们(嗯,新功能?)。

所以我转向实现自定义 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);
}
}
}

在调试器中逐步执行此操作,我注意到这些方法都不会为具有空值的属性调用。

深入研究 JSON.NET 的源代码,我发现(显然,我没有深入研究)有一个特殊情况检查空值,并显式调用 .WriteNull()

对于它的值(value),我确实尝试实现自定义 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}");
}
}

希望这对您有所帮助...

编辑 – 更好地识别 a Nullable<>输入

编辑 – 增加了对字段和属性的支持,也在正常 DynamicValueProvider 之上搭载完成大部分工作,更新测试

关于c# - 在 JSON.NET 中序列化 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8833961/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com