在JSON.NET序列化空 [英] Serializing null in JSON.NET

查看:260
本文介绍了在JSON.NET序列化空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在通过序列化JSON.NET,那就是空写入JSON作为

When serializing arbitrary data via JSON.NET, any property that is null is written to the JSON as

参数propertyName:空

"propertyName" : null

这当然是正确的。

不过,我有一个要求,自动把所有空到默认为空值,例如:空字符串取值应成为的String.Empty ,空诠释?取值应成为 0 ,空布尔? s应该是,系统等。

However I have a requirement to automatically translate all nulls into the default empty value, e.g. null strings should become String.Empty, null int?s should become 0, null bool?s should be false, and so on.

NullValueHandling 是没有帮助的,因为我不想忽略为空,但我也不希望包含他们(嗯,新的功能?)。

NullValueHandling is not helpful, since I dont want to Ignore nulls, but neither do I want to Include them (Hmm, new feature?).

于是我转过身来实现自定义的 JsonConverter
虽然实现本身是一件轻而易举的事,可惜这仍然没有工作 - CanConvert()是从来没有要求,有一个空值,因此属性 WriteJson()不叫任。显然,空值会自动直接序列化为,没有自定义管道。

So I turned to implementing a custom JsonConverter.
While the implementation itself was a breeze, unfortunately this still didnt work - CanConvert() is never called for a property that has a null value, and therefore WriteJson() is not called either. Apparently nulls are automatically serialized directly into null, without the custom pipeline.

例如,这里是一个自定义转换为空字符串的例子:

For example, here is a sample of a custom converter for null strings:

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

通过这个在调试器步进,我指出,无论这些方法都要求有一个空值的属性。

Stepping through this in the debugger, I noted that neither of these methods are called for properties that have a null value.

钻研JSON.NET的源$ C ​​$ C,我发现(显然,我没有去成很多深度)有一个特殊的情况下检查空值和显式调用 .WriteNull( )

Delving into JSON.NET's sourcecode, I found that (apparently, I didnt go into a lot of depth) there is a special case checking for nulls, and explictly calling .WriteNull().

有关它的价值,我也尝试实现自定义的 JsonTextWriter 和覆盖默认 .WriteNull()实施......

For what it's worth, I did try implementing a custom JsonTextWriter and overriding the default .WriteNull() implementation...

public class NullJsonWriter : JsonTextWriter
{
    ... 
    public override void WriteNull()
    {
        this.WriteValue(String.Empty);
    }
}

不过,这并不能很好地工作,因为 WriteNull()方法一无所知的基本数据类型。那么肯定,我可以输出任何空,但是,这并不很好的工作,例如INT,BOOL等。

However, this can't work well, since the WriteNull() method knows nothing about the underlying datatype. So sure, I can output "" for any null, but that doesnt work well for e.g. int, bool, etc.

所以,我的问题 - 短手动将整个数据结构,是对此有任何解决方案或解决方法吗?

So, my question - short of converting the entire data structure manually, is there any solution or workaround for this?

推荐答案

好吧,我想我已经想出了一个解决方案,(我的第一个解决方案是不正确的,在所有的,但后来我又是在火车上)。你需要创建一个特殊的合同解析器和一个自定义ValueProvider为可空类型。试想一下:

Okay, I think I've come up with a solution (my first solution wasn't right at all, but then again I was on the train). You need to create a special contract resolver and a custom ValueProvider for Nullable types. Consider this:

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

然后,我测试了它使用:

Then I tested it using:

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

希望这有助于有点...

Hopefully this helps a bit...

编辑&ndash的;更好地确定了一个可空&LT;&GT; 键入

编辑&ndash的;增加了对域的支持,以及性能,在上方还背负正常 DynamicValueProvider 做的大部分工作,以更新的测试

Edit – Added support for fields as well as properties, also piggy-backing on top of the normal DynamicValueProvider to do most of the work, with updated test

这篇关于在JSON.NET序列化空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆