Search code examples
c#jsonenumsdeserializationhttp-put

Deserialize JSON string into an enum


I'm trying to figure out how to deserialize a JSON string into an enum. Right now I'm taking a serialized Dictionary, passing it to an HttpPut method, and deserializing that string in order to update fields on a custom object using reflection. Here's what I have so far:

I'm putting values into the Dictionary like this:

  Dictionary<string, object> valuesToUpdate = new Dictionary<string, object>();
  valuesToUpdate.Add("Length", 64.0); //Length is a double
  valuesToUpdate.Add("Confidence", SimpleConfidence.THREE); //Confidence is an enum

I'm using JSON to serialize is like this:

string jsonString = JsonConvert.SerializeObject(valuesToUpdate);

I then take the jsonString and send it over to a REST API PUT call. My goal with this is to update various variables for a custom object based on the Key values in the dictionary using reflection (in this example I'll be updating customObject.Confidence and customObject.Length).

The PUT call deserializes the jsonString like this:

Dictionary<string, object> newFields = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);

My plan is to iterate through newFields and use reflection to update customObject's fields. Right now I have some code that works when the dictionary finds strings or doubles but I'm having issues with other types - mainly enums and classes. So basically, how would one go about taking a serialized json dictionary string, deserialize it into the appropriate type for reflection? With the example I've posted, "Length" will update properly, but "Confidence" will throw this error:

Object of type 'System.Int64' cannot be converted to type 'System.Nullable'1.

This is my HttpPut method that reads the jsonString:

[HttpPut("/test/stuff")]
public string PutContact([FromBody]dynamic jsonString)
{
        Dictionary<string, object> newFields = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
        foreach(var field in newFields)
        {
            Console.WriteLine("\nField key: " + field.Key);
            Console.WriteLine("Field value: " + field.Value + "\n");

            PropertyInfo propInfo = typeof(CustomObject).GetProperty(field.Key);
            var value = propInfo.GetValue(customObject, null);
            propInfo.SetValue(customObject, field.Value, null);
        }
}

So it seems likes it's deserializing the original enum into type Int64. How would I go about getting it to recognize it as the original type of SimpleConfidence which is an enum?


Solution

  • The type identity of the enum SimpleConfidence is lost between the serialization and deserialization. You can patch it around by adding some special handling on the assignment part :

    //...
    
    foreach(var field in newFields)
    {
        // ...
    
        PropertyInfo propInfo = typeof(CustomObject).GetProperty(field.Key);
        var value = propInfo.GetValue(customObject, null);
    
        PropertyInfo propInfo = null;
    
        // handles TEnum
        if (propInfo.PropertyType.IsEnum)
        {
            propInfo.SetValue(customObject, Enum.ToObject(propInfo.PropertyType, field.Value), null);
        }
        // handles TEnum?
        else if (Nullable.GetUnderlyingType(propInfo.PropertyType)?.IsEnum == true)
        // if previous line dont compile, use the next 2
        //else if (Nullable.GetUnderlyingType(propInfo.PropertyType) != null &&
        //         Nullable.GetUnderlyingType(propInfo.PropertyType).IsEnum)
        {
            propInfo.SetValue(customObject, Enum.ToObject(Nullable.GetUnderlyingType(propInfo.PropertyType), field.Value), null);
        }
        else
        {
            propInfo.SetValue(customObject, field.Value, null);
        }
    
    }