Json.NET:如何在序列化之前执行对象的隐式转换?

时间:2016-06-23 04:50:55

标签: c# .net json serialization json.net

我有一个有很多'可选bools'的类 - 布尔值可能是true,false或null。在.NET中表示这种情况的最常见方式是使用bool?,但是在内存中占用至少2个字节(请参阅this question),因此我编写了自己的OptionalBool结构只占用1个字节,可以隐式转换为bool?

我的问题是,我有一个这样的课程:

public class PartnerLoginOptions
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string DeviceModel { get; set; }
    public string Version { get; set; }

    public OptionalBool IncludeUrls { get; set; }
    public OptionalBool ReturnDeviceType { get; set; }
    public OptionalBool ReturnUpdatePromptVersions { get; set; }
}

如何在序列化时让Json.NET执行从OptionalBoolbool?的implcit转换?例如,如果IncludeUrlsdefault(OptionalBool)(即'null'),ReturnDeviceType为真且ReturnUpdatePromptVersions为false,则输出的JSON看起来像

{
    "includeUrls": null,
    "returnDeviceType": true,
    "returnUpdatePromptVersions": false
}

如果有PartnerLoginOptions个对象,我怎么能这样做?我到目前为止的代码是

var body = JsonConvert.SerializeObject(options, new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver()
};

修改:如果它有用,hereOptionalBool的源代码。

2 个答案:

答案 0 :(得分:4)

回答您的问题,您可以执行以下操作:

public class PartnerLoginOptions
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string DeviceModel { get; set; }
    public string Version { get; set; }

    [JsonIgnore]
    public OptionalBool IncludeUrls { get; set; }

    [JsonProperty("IncludeUrls")]
    public bool? IncludeUrlsConverted 
    { 
        get { return (bool?)IncludeUrls; } // your conversion here
        set { IncludeUrls = (OptionalBool)value; } // your backwards conversion here
    }
}

或者您可以自己编写JsonConverter

然而,对我而言,OptionalBool看起来像是一个过度工程师。 2个字节绝对不多,我无法想象真正需要它的情况,同时它会产生很多不兼容问题,产生转换器和不同的黑客,并降低可读性。
请考虑更改为bool?

答案 1 :(得分:1)

如果您真的想这样做,可以为OptionalBool定义自定义转换器:

public class OptionalBoolConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(OptionalBool) == objectType;
    }

    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)
    {
        var converted = (bool?) (OptionalBool) value;

        writer.WriteValue(converted);
    }
}

然后以这种方式使用它:

var test = new PartnerLoginOptions
        {
            ReturnDeviceType = true,
            ReturnUpdatePromptVersions = false
        };
        var json = JsonConvert.SerializeObject(test, new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Converters = new JsonConverter[] {new OptionalBoolConverter()}
        });