0

How to achieve below deserialization. value in JSON sometime int and sometime it's decimal. I am working under multiple restrictions so -

  1. can't change value as int property. It may break existing contract and this is use all around system.
  2. have to use MyType as this is use all around system

I noticed decimal in JSON to int deserialization will throw exception.

public class MyType
{
    [JsonProperty("type")]
    [Required]
    public string Type { get; set; }

    [JsonProperty("value")] // existing field 
    public int Value { get; set; }

    [JsonProperty("value")] // new field planning to add for new data
    public decimal Value2 { get; set; }
}
atiyar
  • 7,762
  • 6
  • 34
  • 75
PKV
  • 773
  • 1
  • 7
  • 17
  • 3
    Well, if you're json property isn't reliable about its type, how do you expect your c# code to be? – gunr2171 Mar 01 '21 at 17:14
  • 1
    Also, there is no such thing as "int vs decimal" in JSON - it's a "number", which might or might not have a decimal component. Making the c# property a decimal (or, even better, a float) will always be fine. – gunr2171 Mar 01 '21 at 17:15
  • I would say delegate the setter to the other property, but a `decimal` can be an `int` and an `int` could be a `decimal`; this is an XY problem. – Trevor Mar 01 '21 at 17:23
  • @gunr2171 can't touch int/value combination. When using above, getting "A member with the name 'value' already exists on 'MyType'. Use the JsonPropertyAttribute to specify another name." – PKV Mar 01 '21 at 17:25
  • 3
    You can't have more than one c# property with the same JsonProperty name. You need to decide if you map the JSON property into a int, decimal, or something else. – gunr2171 Mar 01 '21 at 17:26
  • 1
    As gunr2171 has mentioned already, you can't have more than one property with the same json property name; that's why you are getting that error. An option I can think of, in your setter of `Value`, your existing property, check the value first if it's in a specific format you're looking for set `Value2` then otherwise set `Value`. Then remove the `JsonProperty` name from `Value2`. – Trevor Mar 01 '21 at 17:34
  • I don't get it. just split the process. create a data transfer object(DTO) class which has your decimal value and is used for serialization and deserialization. you can convert that object to your target MyType class which has int and decimal splitted up then. – chrisb-de Mar 01 '21 at 17:38

1 Answers1

0

You could leverage a custom JsonConverter. Decorate your class:

[JsonConverter(typeof(CustomConverter))]
public class MyType
{
    [JsonProperty("type")]
    [Required]
    public string Type { get; set; }

    [JsonProperty("value")] // existing field 
    public int Value { get; set; }

    // new field planning to add for new data
    public decimal Value2 { get; set; }
}

Where CustomConverter is defined (roughly):

public class CustomConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jObject = JToken.Load(reader) as JObject;

        MyType myType = new MyType();
        myType.Type = jObject.GetValue("type").ToString();

        JToken tokenValue = jObject["value"];
        if (tokenValue.Type == JTokenType.Integer)
        {
            myType.Value = int.Parse(tokenValue.ToString());
        }
        else if (tokenValue.Type == JTokenType.Float) {
            myType.Value2 = decimal.Parse(tokenValue.ToString());
        }

        return myType;
    }

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

Note that one of Value and Value2 is implicitly set to 0 whereas the other property contains deserialized value.

To test the solution execute:

string json = @"{type:""Type1"",value: 27.99}";
MyType temp = JsonConvert.DeserializeObject<MyType>(json);
matej bobaly
  • 456
  • 3
  • 6