0

I have a class that has lots of 'optional bools'-- boolean values that may be true, false, or null. The most common way to represent this in .NET is to use bool?, however that takes up at least 2 bytes in memory (see this question), so I wrote my own OptionalBool struct that only takes up 1 byte and is implicitly convertible to bool?.

My question is, I have a class like this:

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

How can I get Json.NET to perform the implcit conversion from OptionalBool to bool? while serializing? For example if IncludeUrls was default(OptionalBool) (which is 'null'), ReturnDeviceType was true and ReturnUpdatePromptVersions was false, then the outputted JSON would look something like

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

How can I do this given a PartnerLoginOptions object? The code I have so far is

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

edit: In case it's useful, here is the source code for OptionalBool.

Community
  • 1
  • 1
James Ko
  • 32,215
  • 30
  • 128
  • 239

2 Answers2

4

Answering your question, you can do the following:

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

or you can write your own JsonConverter.

However, for me it looks like your OptionalBool is an overengineering. 2 bytes is absolutely not much, I cannot imagine the case when it is really required, whilst it creates so much incompatibility problems, produces converters and different hacks, and decreases readability.
Consider changing to bool?.

Yeldar Kurmangaliyev
  • 33,467
  • 12
  • 59
  • 101
1

If you're really want to do this you can define custom converter for 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);
    }
}

And then use it this way:

var test = new PartnerLoginOptions
        {
            ReturnDeviceType = true,
            ReturnUpdatePromptVersions = false
        };
        var json = JsonConvert.SerializeObject(test, new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Converters = new JsonConverter[] {new OptionalBoolConverter()}
        });
Aleksey L.
  • 35,047
  • 10
  • 74
  • 84