How to convert object to Dictionary<TKey, TValue> in C#?

187,088

Solution 1

The above answers are all cool. I found it easy to json serialize the object and deserialize as a dictionary.

var json = JsonConvert.SerializeObject(obj);
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);

I don't know how performance is effected but this is much easier to read. You could also wrap it inside a function.

public static Dictionary<string, TValue> ToDictionary<TValue>(object obj)
{       
    var json = JsonConvert.SerializeObject(obj);
    var dictionary = JsonConvert.DeserializeObject<Dictionary<string, TValue>>(json);   
    return dictionary;
}

Use like so:

var obj = new { foo = 12345, boo = true };
var dictionary = ToDictionary<string>(obj);

Solution 2

I use this helper:

public static class ObjectToDictionaryHelper
{
    public static IDictionary<string, object> ToDictionary(this object source)
    {
        return source.ToDictionary<object>();
    }

    public static IDictionary<string, T> ToDictionary<T>(this object source)
    {
        if (source == null)
            ThrowExceptionWhenSourceArgumentIsNull();

        var dictionary = new Dictionary<string, T>();
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
            AddPropertyToDictionary<T>(property, source, dictionary);
        return dictionary;
    }

    private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary)
    {
        object value = property.GetValue(source);
        if (IsOfType<T>(value))
            dictionary.Add(property.Name, (T)value);
    }

    private static bool IsOfType<T>(object value)
    {
        return value is T;
    }

    private static void ThrowExceptionWhenSourceArgumentIsNull()
    {
        throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
    }
}

the usage is just to call .ToDictionary() on an object

Hope it helps.

Solution 3

    public static KeyValuePair<object, object > Cast<K, V>(this KeyValuePair<K, V> kvp)
    {
        return new KeyValuePair<object, object>(kvp.Key, kvp.Value);
    }

    public static KeyValuePair<T, V> CastFrom<T, V>(Object obj)
    {
        return (KeyValuePair<T, V>) obj;
    }

    public static KeyValuePair<object , object > CastFrom(Object obj)
    {
        var type = obj.GetType();
        if (type.IsGenericType)
        {
            if (type == typeof (KeyValuePair<,>))
            {
                var key = type.GetProperty("Key");
                var value = type.GetProperty("Value");
                var keyObj = key.GetValue(obj, null);
                var valueObj = value.GetValue(obj, null);
                return new KeyValuePair<object, object>(keyObj, valueObj);
            }
        }
        throw new ArgumentException(" ### -> public static KeyValuePair<object , object > CastFrom(Object obj) : Error : obj argument must be KeyValuePair<,>");
    }

From the OP:

Instead of converting my whole Dictionary, i decided to keep my obj dynamic the whole time. When i access the keys and values of my Dictionary with a foreach later, i use foreach(dynamic key in obj.Keys) and convert the keys and values to strings simply.

Solution 4

Another option is to use NewtonSoft.JSON.

var dictionary = JObject.FromObject(anObject).ToObject<Dictionary<string, object>>();

Solution 5

this should work:

for numbers, strings, date, etc.:

    public static void MyMethod(object obj)
    {
        if (typeof(IDictionary).IsAssignableFrom(obj.GetType()))
        {
            IDictionary idict = (IDictionary)obj;

            Dictionary<string, string> newDict = new Dictionary<string, string>();
            foreach (object key in idict.Keys)
            {
                newDict.Add(key.ToString(), idict[key].ToString());
            }
        }
        else
        {
            // My object is not a dictionary
        }
    }

if your dictionary also contains some other objects:

    public static void MyMethod(object obj)
    {
        if (typeof(IDictionary).IsAssignableFrom(obj.GetType()))
        {
            IDictionary idict = (IDictionary)obj;
            Dictionary<string, string> newDict = new Dictionary<string, string>();

            foreach (object key in idict.Keys)
            {
                newDict.Add(objToString(key), objToString(idict[key]));
            }
        }
        else
        {
            // My object is not a dictionary
        }
    }

    private static string objToString(object obj)
    {
        string str = "";
        if (obj.GetType().FullName == "System.String")
        {
            str = (string)obj;
        }
        else if (obj.GetType().FullName == "test.Testclass")
        {
            TestClass c = (TestClass)obj;
            str = c.Info;
        }
        return str;
    }
Share:
187,088
Martin Braun
Author by

Martin Braun

Updated on July 05, 2022

Comments

  • Martin Braun
    Martin Braun about 2 years

    How do I convert a dynamic object to a Dictionary<TKey, TValue> in C# What can I do?

    public static void MyMethod(object obj)
    {
        if (typeof(IDictionary).IsAssignableFrom(obj.GetType()))
        {
            // My object is a dictionary, casting the object:
            // (Dictionary<string, string>) obj;
            // causes error ...
        }
        else
        {
            // My object is not a dictionary
        }
    }
    
  • Martin Braun
    Martin Braun almost 12 years
    it get an invalid cast exception if obj is a Dictionary<string, int> (doesnt contain any null keys or values). it seems it got problems to cast the number into a string.
  • Martin Braun
    Martin Braun almost 12 years
    it even throws an invalid cast exception, if i deliver a Dictionary<string, string> on that line. however, thx for the hint, it might be near of my solution.
  • Martin Braun
    Martin Braun almost 12 years
    myTypes[0] and myTypes[1] will be always System.Object. it would help alot to track the types of my dictionary, but it doesnt seems to work. i even need to convert the dictionary to <string, string> at the end, however thx.
  • user1519979
    user1519979 almost 12 years
    it was my fault , to get the types you have to do it with idictionary IDictionary idict = (IDictionary)obj; Type[] myTypes = idict.GetType().GetGenericArguments(); Dictionary<object, object> dict = idict.Cast<dynamic>().ToDictionary(entry => entry.Key, entry => entry.Value);
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen almost 12 years
    Hmm, it's also an ugly solution. Where does obj come from? If only we knew that it was always a Dictionary<,> of some kind, we could make MyMethod generic, and all would be simple and beautiful. The trouble with IDictionary is that it could also be a Hashtable or many other types that are non-generic. And the foreach object type is not even the same (the reason why my answer did not work).
  • Martin Braun
    Martin Braun almost 12 years
    i see, ofc it helps, but its dependent to the given types i pre-code. ive to program independent classes that require to work well with all kinds of types in a Dictionary, even those the programmer creates. Im working on a library I must provide, so.
  • Martin Braun
    Martin Braun almost 12 years
    obj can be any object, just a number (int), any own class i dont kno, any list that contains classes, or in this case, any Dictionary with any unknown classes. my method already works by delivering a dynamic obj and later to convert it to string to store the dictionary as xml (since XmlSerializer hates Dictionaries). now i got some more trouble and reading it and delivering it back without any errors, i might create a new question then later. thank you.
  • user1519979
    user1519979 almost 12 years
    the biggest problem i think is that you have to know how to convert an unknown object to a string. maybe you can force programmers to override the ToString() method in their own classes. e.g.: public abstract class Test { public abstract String ToString(); } class TestClass : Test { public override string ToString() { return "This is a test"; } } so you can check if the object is a type of the abstract class and then use the tostring method otherwise you will get allways the classname with tostring(not very usefull in my opinion) :)
  • dizel3d
    dizel3d over 7 years
    The question is not "How to convert IDictionary objects to IDictionary<T,V>?". The question is "How to convert Object objects to IDictionary<string, Object>?".
  • Simon
    Simon about 5 years
    @UserID0908 no worries. BTW i updated it to modern c#
  • David Savage
    David Savage about 5 years
    Great lateral thinking! I would then put this in an extension: ``` public static class Extensions { public static IDictionary<string, object> ToDictionary( this object o) { var j = JsonConvert.SerializeObject(o); var value = JsonConvert .DeserializeObject<IDictionary<string, object>>(j); return value; } } ```
  • amackay11
    amackay11 almost 5 years
    I went with this approach but discovered it is quite slow so use with caution! My application ground to a snails pace when calling for several hundred dictionaries.
  • Mohaimin Moin
    Mohaimin Moin almost 4 years
    How to call MyMethod method from other place?
  • Dmitry Gusarov
    Dmitry Gusarov almost 4 years
    Keep in mind that this approach will convert Int32 to Int64 because JSON don't have strong enough typing and basically have 'number' for everything
  • iBobb
    iBobb over 3 years
    Thanks, I also had to filter out 2 of the properties of the object: var metadata = JObject.FromObject(houseObject).ToObject<Dictionary<string, string>>().Where(x => x.Key != "IsRented" && x.Key != "HasBeenRenovated").ToDictionary(it => it.Key, it => it.Value);
  • Ricardo
    Ricardo over 2 years
    Not work with nested objects
  • Auspex
    Auspex about 2 years
    Lovely. I was just thinking about this, and my thought was to serialize/deserialize and just googled to see if there was a better way. :)
  • Auspex
    Auspex about 2 years
    Er... Dictionary<string, string> dicEditdata = obj as Dictionary<string, string>;, perhaps?