81

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
  • 10,906
  • 9
  • 64
  • 105
  • You check that your object is an `IDictionary`. So casting to that interface, like `(IDictionary)obj`, will succeed. There are many other `IDictionary` than `Dictionary` though. So you better test the same type you want to cast to. I agree with Nikhil (answerer) that you want to use `as` in this case. I can provide details if needed. – Jeppe Stig Nielsen Jul 20 '12 at 09:54
  • 1
    In general consider the answers here: http://stackoverflow.com/questions/3481923/in-c-sharp-convert-anonymous-type-into-key-value-array (e.g. `RouteValueDictionary`) – Jacob Foshee Aug 03 '15 at 18:27

19 Answers19

140

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);
christo8989
  • 6,442
  • 5
  • 37
  • 43
  • 2
    Great lateral thinking! I would then put this in an extension: ``` public static class Extensions { public static IDictionary ToDictionary( this object o) { var j = JsonConvert.SerializeObject(o); var value = JsonConvert .DeserializeObject>(j); return value; } } ``` – David Savage Jun 05 '19 at 11:21
  • 4
    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. – amackay11 Jul 25 '19 at 18:05
  • 2
    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 – Dmitry Gusarov Sep 20 '20 at 22:40
  • 3
    Not work with nested objects – Ricardo Dec 01 '21 at 13:57
  • 1
    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 Jun 14 '22 at 20:46
  • This no longer works with the latest System.Text.Json – yfeng Jan 27 '23 at 22:58
  • 1
    @yfeng its newton, not System.Text.Json – Niels Lucas Jul 20 '23 at 10:20
56

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.

d.popov
  • 4,175
  • 1
  • 36
  • 47
25
    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.

George Stocker
  • 57,289
  • 29
  • 176
  • 237
cuongvn_it
  • 251
  • 3
  • 3
23

Another option is to use NewtonSoft.JSON.

var dictionary = JObject.FromObject(anObject).ToObject<Dictionary<string, object>>();
Bigtoe
  • 3,372
  • 1
  • 31
  • 47
  • 1
    Thanks, I also had to filter out 2 of the properties of the object: `var metadata = JObject.FromObject(houseObject).ToObject>().Where(x => x.Key != "IsRented" && x.Key != "HasBeenRenovated").ToDictionary(it => it.Key, it => it.Value);` – iBobb Jan 20 '21 at 13:56
12

If you don't mind LINQ Expressions;

public static Dictionary<string, object> ConvertFromObjectToDictionary(object arg)
{
     return arg.GetType().GetProperties().ToDictionary(property => property.Name, property => property.GetValue(arg));
}
Jim G.
  • 15,141
  • 22
  • 103
  • 166
mcemmy
  • 9,232
  • 1
  • 11
  • 4
7

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;
    }
user1519979
  • 1,854
  • 15
  • 26
  • 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 at the end, however thx. – Martin Braun Jul 20 '12 at 11:09
  • 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 dict = idict.Cast().ToDictionary(entry => entry.Key, entry => entry.Value);` – user1519979 Jul 20 '12 at 11:33
  • 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 Jul 20 '12 at 13:55
  • 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) :) – user1519979 Jul 23 '12 at 09:46
3

Assuming key can only be a string but value can be anything try this

public static Dictionary<TKey, TValue> MyMethod<TKey, TValue>(object obj)
{
    if (obj is Dictionary<TKey, TValue> stringDictionary)
    {
        return stringDictionary;
    }

    if (obj is IDictionary baseDictionary)
    {
        var dictionary = new Dictionary<TKey, TValue>();
        foreach (DictionaryEntry keyValue in baseDictionary)
        {
            if (!(keyValue.Value is TValue))
            {
                // value is not TKey. perhaps throw an exception
                return null;
            }
            if (!(keyValue.Key is TKey))
            {
                // value is not TValue. perhaps throw an exception
                return null;
            }

            dictionary.Add((TKey)keyValue.Key, (TValue)keyValue.Value);
        }
        return dictionary;
    }
    // object is not a dictionary. perhaps throw an exception
    return null;
}
Simon
  • 33,714
  • 21
  • 133
  • 202
3
   public static void MyMethod(object obj){
   Dictionary<string, string> dicEditdata = data as Dictionary<string, string>;
   string abc=dicEditdata["id"].ToString();} 

suppose--- if you place the cursor over the object(obj) while debugging and if you get an object with the value {['id':'ID1003']} then you can use the value as

string abc=dicEditdata["id"].ToString(); 
Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
Lijin Durairaj
  • 4,910
  • 15
  • 52
  • 85
2

I've done something like this and works for me.

using System.ComponentModel;

var dictionary = new Dictionary<string, string>();

foreach (var propDesc in TypeDescriptor.GetProperties(Obj))
{
    if (!string.IsNullOrEmpty(propDesc.GetValue(Obj)))
    {
        dictionary.Add(propDesc.Name, propDesc.GetValue(Obj));
    }
}

Also, another alternative and innovative solution is here.

var dictionary = new System.Web.Routing.RouteValueDictionary(Obj);
Mahib
  • 3,977
  • 5
  • 53
  • 62
2

I hope this could work :)

    //  obj = new { a = "string", b = 0, c = true };
    static Dictionary<string, object> ToDictionary(object obj)
    {
        int i = 0;
        var props = obj.GetType().GetProperties();
        return props.ToDictionary(k => props[i].Name, v => props[i++].GetValue(obj));
    }
cartory
  • 31
  • 1
  • 4
  • 1
    There are **17 existing answers** to this question, including a top-voted, accepted answer with over **one hundred votes**. Are you _certain_ your solution hasn't already been given? If not, why do you believe your approach improves upon the existing proposals, which have been validated by the community? Offering an explanation is _always_ useful on Stack Overflow, but it's _especially_ important where the question has been resolved to the satisfaction of both the OP and the community. Help readers out by explaining what your answer does different and when it might be preferred. – Jeremy Caney Mar 01 '22 at 00:11
  • That seems harsh, but … does this work? It looks wrong to me. Shouldn't there be a `for` loop or a `ForEach()` method? – Auspex Jun 14 '22 at 20:57
1

This code securely works to convert Object to Dictionary (having as premise that the source object comes from a Dictionary):

    private static Dictionary<TKey, TValue> ObjectToDictionary<TKey, TValue>(object source)
    {
        Dictionary<TKey, TValue> result = new Dictionary<TKey, TValue>();

        TKey[] keys = { };
        TValue[] values = { };

        bool outLoopingKeys = false, outLoopingValues = false;

        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
        {
            object value = property.GetValue(source);
            if (value is Dictionary<TKey, TValue>.KeyCollection)
            {
                keys = ((Dictionary<TKey, TValue>.KeyCollection)value).ToArray();
                outLoopingKeys = true;
            }
            if (value is Dictionary<TKey, TValue>.ValueCollection)
            {
                values = ((Dictionary<TKey, TValue>.ValueCollection)value).ToArray();
                outLoopingValues = true;
            }
            if(outLoopingKeys & outLoopingValues)
            {
                break;
            }
        }

        for (int i = 0; i < keys.Length; i++)
        {
            result.Add(keys[i], values[i]);
        }

        return result;
    }
Antonio Leonardo
  • 1,805
  • 1
  • 8
  • 18
1

This way for object array to Dictionary<string, object> List coverting

object[] a = new object[2];
var x = a.Select(f => (Dictionary<string, object>)f).ToList();

This way for single object to Dictionary<string, object> coverting

object a = new object;
var x = (Dictionary<string, object>)a;
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
0

You can create a generic extension method and then use it on the object like:

public static class Extensions
{
    public static KeyValuePair<TKey, TValue> ToKeyValuePair<TKey, TValue>(this Object obj)
    {
        // if obj is null throws exception
        Contract.Requires(obj != null);

        // gets the type of the obj parameter
        var type = obj.GetType();
        // checks if obj is of type KeyValuePair
        if (type.IsGenericType && type == typeof(KeyValuePair<TKey, TValue>))
        {

            return new KeyValuePair<TKey, TValue>(
                                                    (TKey)type.GetProperty("Key").GetValue(obj, null), 
                                                    (TValue)type.GetProperty("Value").GetValue(obj, null)
                                                 );

        }
        // if obj type does not match KeyValuePair throw exception
        throw new ArgumentException($"obj argument must be of type KeyValuePair<{typeof(TKey).FullName},{typeof(TValue).FullName}>");   
 }

and usage would be like:

KeyValuePair<string,long> kvp = obj.ToKeyValuePair<string,long>();
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
0

I use this simple method:

public Dictionary<string, string> objToDict(XYZ.ObjectCollection objs) {
    var dict = new Dictionary<string, string>();
    foreach (KeyValuePair<string, string> each in objs){
        dict.Add(each.Key, each.Value);
    }
    return dict;
}
T.Todua
  • 53,146
  • 19
  • 236
  • 237
0

You can use this:

Dictionary<object,object> mydic = ((IEnumerable)obj).Cast<object>().ToList().ToDictionary(px => px.GetType().GetProperty("Key").GetValue(px), pv => pv.GetType().GetProperty("Value").GetValue(pv));
Davoud
  • 17
  • 6
0
    string BaseUrl = "http://www.example.com";
    HttpClient client = new HttpClient { BaseAddress = new Uri(BaseUrl) };    
    PropertyInfo[] properties = object.GetType().GetProperties();
    Dictionary<string, string> dictionary = new Dictionary<string, string>();
    foreach (PropertyInfo property in properties)
    {
      dictionary.Add(property.Name, property.GetValue(model, null).ToString());
    }
               
    foreach (string key in dictionary.Keys)
    {
      client.DefaultRequestHeaders.Add(key, dictionary[key]);
    }
-1

As I understand it, you're not sure what the keys and values are, but you want to convert them into strings?

Maybe this can work:

public static void MyMethod(object obj)
{
  var iDict = obj as IDictionary;
  if (iDict != null)
  {
    var dictStrStr = iDict.Cast<DictionaryEntry>()
      .ToDictionary(de => de.Key.ToString(), de => de.Value.ToString());

    // use your dictStrStr        
  }
  else
  {
    // My object is not an IDictionary
  }
}
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • it get an invalid cast exception if obj is a Dictionary (doesnt contain any null keys or values). it seems it got problems to cast the number into a string. – Martin Braun Jul 20 '12 at 10:40
  • it even throws an invalid cast exception, if i deliver a Dictionary on that line. however, thx for the hint, it might be near of my solution. – Martin Braun Jul 20 '12 at 10:54
  • 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). – Jeppe Stig Nielsen Jul 20 '12 at 11:48
  • 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. – Martin Braun Jul 20 '12 at 14:00
-1
object parsedData = se.Deserialize(reader);
System.Collections.IEnumerable stksEnum = parsedData as System.Collections.IEnumerable;

then will be able to enumerate it!

Zakari
  • 453
  • 4
  • 15
-3

Simple way:

public IDictionary<T, V> toDictionary<T, V>(Object objAttached)
{
    var dicCurrent = new Dictionary<T, V>();
    foreach (DictionaryEntry dicData in (objAttached as IDictionary))
    {
        dicCurrent.Add((T)dicData.Key, (V)dicData.Value);
    }
    return dicCurrent;
}
MiBol
  • 1,985
  • 10
  • 37
  • 64
  • The question is not "How to convert IDictionary objects to IDictionary?". The question is "How to convert Object objects to IDictionary?". – dizel3d Feb 03 '17 at 11:38