1

I have the following json:

"rates": {
        "AT": {
            "country": "Austria",
            "standard_rate": 20.00,
            "reduced_rate": 10.00,
            "reduced_rate_alt": 13.00,
            "super_reduced_rate": false,
            "parking_rate": 12.00
        },
        "DK": {
            "country": "Denmark",
            "standard_rate": 25.00,
            "reduced_rate": false,
            "reduced_rate_alt": false,
            "super_reduced_rate": false,
            "parking_rate": false
        },
}

And I have the following class to deserialize the json:

    public string country { get; set; }
    public double standard_rate { get; set; }
    //public string reduced_rate { get; set; }
    private double _reduced_rate;

    public double reduced_rate
    {
        get { return _reduced_rate; }
        set
        {
            bool isDouble = Double.TryParse(value.ToString(), out _reduced_rate);
            if (isDouble)
                _reduced_rate = value;
            else
                _reduced_rate = 0.0;
        }
    }

    public string reduced_rate_alt { get; set; }
    public string super_reduced_rate { get; set; }
    public string parking_rate { get; set; }

And when the value of reduce_rate is a false I want to set a 0.0 else the double value. But in the set method never enters into the else.

Is there another approach to resolve this situation?

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
Fabio Santos
  • 253
  • 1
  • 4
  • 15
  • 1
    Well the value of `value` in the setter is a `double`, so why would you expect to *not* be able to parse it? Do you absolutely have to work with this JSON? Having a property which can either be a double or a Boolean value seems *horrible* to me. You may find it's simplest to have a two-stage process, where you first convert this into sensible JSON. As an aside, I strongly recommend that you follow .NET naming conventions for your properties, and use attributes to specify how they're serialized in JSON. – Jon Skeet Sep 06 '16 at 11:25
  • The json source from https://euvatrates.com/rates.json. i can't change the json – Fabio Santos Sep 06 '16 at 11:27
  • it already does what you want. If you want to test it, you can write unite test and pass the mock json data instead of getting it from the actual source. – Carbine Sep 06 '16 at 11:37
  • Actually false should be 0 so this in double is 0.00, it does what you want. you don´t need the 'else' – Marcel Theis Sep 06 '16 at 11:40
  • So, why the deserialize faills because the value is false? the line it fails is the follow:`var rates = JsonConvert.DeserializeObject(jstr).rates; ` – Fabio Santos Sep 06 '16 at 11:44
  • What will happens if you define `reduced_rate` as `object`? Will serializer throw? What type will be in the setter? If that doesn't work, you can always deserialize something (or everything) [manually](http://stackoverflow.com/a/4749755/1997232). – Sinatr Sep 06 '16 at 12:08
  • If I put as string doesn't crash – Fabio Santos Sep 06 '16 at 12:12

1 Answers1

4

One way to handle this would be to define reduced_rate_alt as a string and then define a new property which reads and tries to parse that to a value in the getter. That can work but you have several like that and since using JSON.NET, the same converter should work with all of them, I'd manually convert those properties:

[JsonConverter(typeof(RateJsonConverter))]
public decimal reduced_rate_alt { get; set; }

Adorn each of the properties which might return false with that attribute. This tells JSON.NET that you are supplying the code to deserialize this property. While you are at it you may want to also fix up the property names with [JsonProperty].

The rule/conversion implements is simply to use 0 for false otherwise the value. As long as the conversion rule is the same for all of them, you can use the same converter for each property. I also changed the type to decimal which is probably more appropriate for these.

public class RateJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {   // name used in a previous answer
        return (objectType == typeof(VRate));
    }

    public override object ReadJson(JsonReader reader, Type objectType, 
                                object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        decimal d = 0M;

        Decimal.TryParse(token.ToString(), out d);        
        return d;
    }

    public override void WriteJson(JsonWriter writer, object value,
                    JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Testing:

var rates = JsonConvert.DeserializeObject<VRates>(jstr).rates;

foreach (KeyValuePair<string, VRate> kvp in rates)
{
    Console.WriteLine("key: {0} ({1}), reduced alt rate: {2}", kvp.Key, 
        kvp.Value.country,
        kvp.Value.reduced_rate_alt.ToString("F2"));
    kvp.Value.VTag = kvp.Key;
}

Output for the first few:

key: AT (Austria), reduced alt rate: 13.00
key: BE (Belgium), reduced alt rate: 6.00
key: BG (Bulgaria), reduced alt rate: 0.00
key: CY (Cyprus), reduced alt rate: 5.00
key: CZ (Czech Republic), reduced alt rate: 10.00
key: DK (Denmark), reduced alt rate: 0.00

BG and DK are false and convert to 0, while the others have the rate listed in the JSON.

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178