Return generic type from dictionary (else return a default generic value)

I'm trying to pass a key to a dictionary (of objects) and get the value out (which could be various types) or fallback to a default value I supplied.

For example

// Called from some other method
// It should look in the dictionary for that key and return the value
// else return the int 365
GetValueFromSetting("numDaysInYear", 365)

public static T GetValueFromSettings<T>(string key, T defaultValue)
{
    // Settings is a dictionary, which I get in json form
    Dictionary<string, object> settingsDictionary = (Dictionary<string, object>)ParseConfig.CurrentConfig.Get<Dictionary<string, object>>("settings");

    if(settingsDictionary.ContainsKey(key))
    {
        return settingsDictionary[key];
    }

    return defaultValue;
}   

Firstly I was getting. Cannot implicitly convert type object to T. An explicit conversion exists (are you missing a cast?)

So I cast the key return with

return (T)settingsDictionary[key];

This got rid of the compile error but I have InvalidCastExpections. For instance in the json numbers are stored as 35.0 (which would be a double) and if I call:

GetValueFromSettings("someOffset", 32.0f);

I'll get an InvalidCastExpection when it finds the key in the json as 32.0 and tries to convert to a float.

I also tried using a generic instead of object:

public static T GetValueFromSettings<T>(string key, T defaultValue)
{
    // Settings is a dictionary, which I get in json form
    Dictionary<string, T> settingsDictionary = (Dictionary<string, T>)ParseConfig.CurrentConfig.Get<Dictionary<string, T>>("settings");

    if(settingsDictionary.ContainsKey(key))
    {
        return settingsDictionary[key];
    }

    return defaultValue;
}   

In the hope that it would fix it but that also results in an invalid cast exception. This time it's on the dictionary though as the json expects a type of Dictionary.

I've also seen System.Convert.ChangeType() but again no luck.

Any help would be appreciated.

Jon Skeet
people
quotationmark

What you're seeing (in the first case) is that you can't unbox from int to float. What you're seeing when casting the dictionary itself is that a Dictionary<string, object> isn't a Dictionary<string, float>, which seems entirely reasonable to me.

You might want to use:

// I don't *expect* that you need a cast herem, given the type argument
var settingsDictionary = ParseConfig.CurrentConfig.Get<Dictionary<string, object>>("settings");
object value;
if (!settingsDictionary.TryGetValue(key, out value))
{
    return defaultValue;
}
object converted = Convert.ChangeType(value, typeof(T));
return (T) converted;

That will handle far more conversions - but it will throw an exception if there's no suitable conversion available.

people

See more on this question at Stackoverflow