Mapping object to dictionary and vice versa

155,247

Solution 1

Using some reflection and generics in two extension methods you can achieve that.

Right, others did mostly the same solution, but this uses less reflection which is more performance-wise and way more readable:

public static class ObjectExtensions
{
    public static T ToObject<T>(this IDictionary<string, object> source)
        where T : class, new()
    {
            var someObject = new T();
            var someObjectType = someObject.GetType();

            foreach (var item in source)
            {
                someObjectType
                         .GetProperty(item.Key)
                         .SetValue(someObject, item.Value, null);
            }

            return someObject;
    }

    public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
    {
        return source.GetType().GetProperties(bindingAttr).ToDictionary
        (
            propInfo => propInfo.Name,
            propInfo => propInfo.GetValue(source, null)
        );

    }
}

class A
{
    public string Prop1
    {
        get;
        set;
    }

    public int Prop2
    {
        get;
        set;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, object> dictionary = new Dictionary<string, object>();
        dictionary.Add("Prop1", "hello world!");
        dictionary.Add("Prop2", 3893);
        A someObject = dictionary.ToObject<A>();

        IDictionary<string, object> objectBackToDictionary = someObject.AsDictionary();
    }
}

Solution 2

Convert the Dictionary to JSON string first with Newtonsoft.

var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);

Then deserialize the JSON string to your object

var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);

Solution 3

Seems reflection only help here.. I've done small example of converting object to dictionary and vise versa:

[TestMethod]
public void DictionaryTest()
{
    var item = new SomeCLass { Id = "1", Name = "name1" };
    IDictionary<string, object> dict = ObjectToDictionary<SomeCLass>(item);
    var obj = ObjectFromDictionary<SomeCLass>(dict);
}

private T ObjectFromDictionary<T>(IDictionary<string, object> dict)
    where T : class 
{
    Type type = typeof(T);
    T result = (T)Activator.CreateInstance(type);
    foreach (var item in dict)
    {
        type.GetProperty(item.Key).SetValue(result, item.Value, null);
    }
    return result;
}

private IDictionary<string, object> ObjectToDictionary<T>(T item)
    where T: class
{
    Type myObjectType = item.GetType();
    IDictionary<string, object> dict = new Dictionary<string, object>();
    var indexer = new object[0];
    PropertyInfo[] properties = myObjectType.GetProperties();
    foreach (var info in properties)
    {
        var value = info.GetValue(item, indexer);
        dict.Add(info.Name, value);
    }
    return dict;
}

Solution 4

I'd highly recommend the Castle DictionaryAdapter, easily one of that project's best-kept secrets. You only need to define an interface with the properties you want, and in one line of code the adapter will generate an implementation, instantiate it, and synchronize its values with a dictionary you pass in. I use it to strongly-type my AppSettings in a web project:

var appSettings =
  new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);

Note that I did not need to create a class that implements IAppSettings - the adapter does that on the fly. Also, although in this case I'm only reading, in theory if I were setting property values on appSettings, the adapter would keep the underlying dictionary in sync with those changes.

Solution 5

Reflection can take you from an object to a dictionary by iterating over the properties.

To go the other way, you'll have to use a dynamic ExpandoObject (which, in fact, already inherits from IDictionary, and so has done this for you) in C#, unless you can infer the type from the collection of entries in the dictionary somehow.

So, if you're in .NET 4.0 land, use an ExpandoObject, otherwise you've got a lot of work to do...

Share:
155,247

Related videos on Youtube

Saw
Author by

Saw

Enthusiastic, highly motivated, strategic thinker, and collaborative software technologist, heavily experienced in System Architecture, Integration, and Web Development with extensive knowledge in ID document solutions and enterprise software development, product management, and project management. I enjoy challenging work environment to apply my knowledge for a forward-thinking company that embraces cutting-edge, world-class technology. London, UK

Updated on July 08, 2022

Comments

  • Saw
    Saw almost 2 years

    Are there any elegant quick way to map object to a dictionary and vice versa?

    Example:

    IDictionary<string,object> a = new Dictionary<string,object>();
    a["Id"]=1;
    a["Name"]="Ahmad";
    // .....
    

    becomes

    SomeClass b = new SomeClass();
    b.Id=1;
    b.Name="Ahmad";
    // ..........
    
    • Konrad
      Konrad about 4 years
      fastest way would be by code-generation like protobuf... I used expression trees to avoid reflection as often as possible
    • Cesar
      Cesar almost 4 years
      All the self-coded answers below do not support deep conversion and will not work in real life applications. You should use some library like Newtonsoft as suggested by earnerplates
  • Matías Fidemraizer
    Matías Fidemraizer over 13 years
    For what you want to use an activator if you can use the "new" generic constraint? :)
  • TurBas
    TurBas over 13 years
    @Matías Fidemraizer You are absolutely right. My mistake. Changed it.
  • nolimit
    nolimit over 11 years
    I like the implementation, I actually started using it, but do you have any feedback on performance? I know that reflection is not the greatest when it comes to performance? do you have any comments?
  • Matías Fidemraizer
    Matías Fidemraizer over 11 years
    @nolimit Actually I don't know its actual performance, but I guess it's not that bad (worst than avoiding reflection, of course...). In fact, what's the alternative? Depending on projects' requirements, maybe there're other options, like using dynamic typing which is far faster than reflection... Who knows! :)
  • nolimit
    nolimit over 11 years
    well in my case the alternative is as simple as building the object by assignment, but I'm looking for a neat yet inexpensive way to build an object. Having said that, I have found this which means to me that it's not too expensive to use that piece of code.
  • Matías Fidemraizer
    Matías Fidemraizer over 11 years
    @nolimit Yeah, it seems that there's no problem. It's just about using the right tool for the required problem :D In your case, it should work like a charm. I believe I can tune up something in the code yet!
  • Matías Fidemraizer
    Matías Fidemraizer over 11 years
    @nolimit Check that now GetType() isn't called on someObject for each property anymore in the first method.
  • Shiva
    Shiva over 10 years
    I guess the "best-kept secret" died a lonely death. The Castle DictionaryAdapter link above, as well as the Download links for "DictionaryAdapter" on castleproject.org all go to a 404 Page :(
  • Gaspar Nagy
    Gaspar Nagy over 10 years
    No! It's still in the Castle.Core. I have fixed the link.
  • regisbsb
    regisbsb over 10 years
    I won't use it as it replaces "_" with "-". And you need MVC. Use the pure Routing class: new RouteValueDictionary(objectHere);
  • Sunil Chaudhary
    Sunil Chaudhary almost 6 years
    Thanks u r awesome, one issue if someclass has not some of the properties which are in dictionary. It should match only properties exists in someclass and skip other, as of now I used try catch any better option for this?
  • baikho
    baikho almost 6 years
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.
  • amackay11
    amackay11 almost 5 years
    Use this approach with caution. It will bog down your application if used for many (hundreds) of dictionaries.
  • bikeman868
    bikeman868 almost 5 years
    Castle was a great library that got overlooked somehow
  • Cesar
    Cesar almost 4 years
    This doesn't support nesting.
  • Francesco D.M.
    Francesco D.M. almost 4 years
    Very nice solution, but if I'm not mistaken this would not handle nested properties right?
  • Ivan Castellanos
    Ivan Castellanos over 3 years
    This solution doesn't work for anonymous objects (e.g when you don't have a type to convert to), for that see stackoverflow.com/a/7596697/800817
  • Adjit
    Adjit about 3 years
    @Cesar yes it does. You would just have to implement it. Maybe recursion on PropertyInfo