Search code examples
c#jsongenericsanonymous-objects

C# generic utility to check JSON string for anonymous type


I have a JSON string. I want to check if it contains an anonymous object. If it does then return the value. If it doesn't then return a default value. I then want to be able to repeat this multiple times for different anonymous objects.

Here is a sample of the code that I have currently implemented but obviously it is duplicated each time and not very "clean".

var displayDataBy = 0;
var displayDataByDefinition = new { DisplayDataBy = new { Key = "string", Value = displayDataBy } };
var displayDataByResult = JsonConvert.DeserializeAnonymousType(this.OhdContentPageParameters, displayDataByDefinition);
try { displayDataBy = displayDataByResult.DisplayDataBy.Value; }
catch { }

var xMinsOeeToShow = 480;
var xMinsOeeToShowDefinition = new { XMinsOeeToShow = new { Key = "string", Value = xMinsOeeToShow } };
var xMinsOeeToShowResult = JsonConvert.DeserializeAnonymousType(this.OhdContentPageParameters, xMinsOeeToShowDefinition);
try { xMinsOeeToShow = xMinsOeeToShowResult.XMinsOeeToShow.Value; }
catch { }

I would prefer it was a generic method that I could call for each anonymous type. Also it would be nice to not have to rely on the try/catch. Can it be done?

UPDATE...

This is working great for int, bool and double:

public static T2 DeserializeValue<T, T2>(this string json, T definition, T2 defaultValue, Func<T, T2?> getValueFunc) where T2 : struct
{
    var jsonAnon = JsonConvert.DeserializeAnonymousType(json, definition);
    return getValueFunc(jsonAnon) ?? defaultValue;
}

I added this for strings:

public static string DeserializeStringValue<T>(this string json, T definition, string defaultValue, Func<T, string> getValueFunc)
{
    var jsonAnon = JsonConvert.DeserializeAnonymousType(json, definition);
    return getValueFunc(jsonAnon) ?? defaultValue;
}

Solution

  • Using a helper class to generalize the operations you are performing,

    public static class DeserializeHelpers {
        public static T2 DeserializeValue<T,T2>(this string s, T def, T2 defans, Func<T, T2?> getAnsFn) where T2 : struct {
            var jsonAnon = JsonConvert.DeserializeAnonymousType(s, def);
            return getAnsFn(jsonAnon) ?? defans;
        }
    
        public static T2 DeserializeClass<T,T2>(this string s, T def, T2 defans, Func<T, T2> getAnsFn) where T2 : class {
            var jsonAnon = JsonConvert.DeserializeAnonymousType(s, def);
            return getAnsFn(jsonAnon) ?? defans;
        }
    }
    

    You can slightly simplify your code as follows. I left in some of the verbose coding as you seemed to be going to great lengths to avoid putting in an explicit type for Value but I was forced to assume it was a value type to allow for null returns from the member accessor lambda. If a class might be returned, you would need to use the class helper.

    var displayDataBy = 0;
    var displayDataByDefinition = new { DisplayDataBy = new { Key = "string", Value = displayDataBy } };
    var displayDataByResult = this.OhdContentPageParameters.DeserializeValue(displayDataByDefinition, displayDataBy, x => x.DisplayDataBy?.Value);
    
    var xMinsOeeToShow = 480;
    var xMinsOeeToShowDefinition = new { XMinsOeeToShow = new { Key = "string", Value = xMinsOeeToShow } };
    var xMinsOeeToShowResult = this.OhdContentPageParameters.DeserializeValue(xMinsOeeToShowDefinition, xMinsOeeToShow, x => x.XMinsOeeToShow?.Value);
    

    I used an extension method for Deserialize... but of course it could be a regular method.

    If you don't need to reuse the anonymous type definition you could pass that inline to the Deserialize... method.