Home > Enterprise >  How to make generic method for extracting different types from Dictionary<string, object>
How to make generic method for extracting different types from Dictionary<string, object>

Time:11-22

I want to make one method which will be responsible to get value based on input arg key and to lookup for type of that value because its an object (can be int, string, datetime...)

I created something like this:

public T GetValueForKeyFromHeader<T> (string key)
{
 object value = null;
 var hasValue = Headers?.TryGetValue(key, out value!); //IDcitionary<string, object>
 return (T)Convert.ChangeType(typeof(value), typeof(T)); 
//here on this line I have an error: 'value' is a variable but its used like a type
}

some examples of this IDictionary collection: //"apiKeyId", "guid" //"CorrelationId", 333 // "test": "hello world"

I want to extract these values, and to put them in my non-anemic model for each property:

public string Test{get;set;} = GetValueForKeyFromHeader("test");
public int CorrelationId{get;set;} = GetValueForKeyFromHeader("CorrelationId");
public string ApiKeyId {get;set;} = GetValueForKeyFromHeader("api_key_id");

CodePudding user response:

In my experience, TypeDescriptor is the way to go :

public static bool TryGetValue<TValue>(this IDictionary<string, object> self, string key, out TValue value)
{
    if (!self.TryGetValue(key, out var _value))
    {
        value = default;
        return false;
    }
    if (_value is TValue casted)
    {
        value = casted;
        return true;
    }
    if (_value is string str)
    {
        var converter = TypeDescriptor.GetConverter(typeof(TValue));
        if (converter.CanConvertFrom(typeof(string)))
        {
            value = (TValue)converter.ConvertFromInvariantString(str);
            return true;
        }
    }
    value = default;
    return false;
}

Then you can rewrite your method:

public T GetValueForKeyFromHeader<T> (string key)
{
    return Headers?.TryGetValue(key, out var value) == true ? value : default;
}

CodePudding user response:

You're using Convert.ChangeType incorrectly, you need to pass the object that you want to convert.

return (T)Convert.ChangeType(value, typeof(T));

Seeing as you're not actually using the result of TryGetValue, it may also be simpler to simply access the object by its key. If it doesn't exist you'll get a KeyNotFoundException, in my opinion this would be more clear than the InvalidCastException you'll currently receive for passing null.

var value = Headers[key];
return (T)Convert.ChangeType(value, typeof(T));
  • Related