97

Can I convert Class into Dictionary<string, string>?

In Dictionary I want my class properties as keys and value of particular a property as the value.

Suppose my class is

public class Location
{
    public string city { get; set; }
    public string state { get; set; }
    public string country { get; set;
}

Now suppose my data is

city = Delhi
state = Delhi
country = India

Now you can understand my point easily!

I want to make a Dictionary! That dictionary should be like:

Dictionary<string,string> dix = new Dictionary<string,string> ();
dix.add("property_name", "property_value");

I can get the value! But how can I get property names (not value)?

What should I code to create it dynamic? That should work for every class which I want.

You can understand this question as:

How can I get a list of properties from particular class?

Now again I am explaining one of my eagernesses about Dictionary! This question popuped in my mind from answer of my previous question!!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Chintan
  • 2,768
  • 4
  • 27
  • 43
  • Can you try to reword the question please? I have no real idea what you are trying to achieve. – ilivewithian Feb 09 '12 at 12:00
  • Insort ! I want all variables' name of particular class ! Is this possible ? – Chintan Feb 09 '12 at 12:02
  • @NoOne I've answered you, but you need to learn something more about OOP. You're talking about _properties_. And class-level "variables" are called _fields_. It's important to call everything by its name as understanding you'd easier than now! ;) – Matías Fidemraizer Feb 09 '12 at 12:06
  • @MatíasFidemraizer Sorry ! My mistake I should use "property" I have edited ! – Chintan Feb 09 '12 at 12:11
  • @Chintan I dont know where you plan on using a dictionary of a class, note, that in contrary to your class where "Country" can be a property of type `Country` and city is of type `string`, in a dictionary you have to specify the most basic type you are going to store (most likely `object`) which will make your life harder further along the road. – Tomer W Jan 16 '17 at 13:17
  • Does this answer your question? [How to convert object to Dictionary in C#?](https://stackoverflow.com/questions/11576886/how-to-convert-object-to-dictionarytkey-tvalue-in-c) – Jim G. Apr 28 '22 at 17:02

9 Answers9

247

This is the recipe: 1 reflection, 1 LINQ-to-Objects!

 someObject.GetType()
     .GetProperties(BindingFlags.Instance | BindingFlags.Public)
          .ToDictionary(prop => prop.Name, prop => (string)prop.GetValue(someObject, null))

Since I published this answer I've checked that many people found it useful. I invite everyone looking for this simple solution to check another Q&A where I generalized it into an extension method: Mapping object to dictionary and vice versa

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • what if I see "intrinsic" properties like "GenericEqualityComparer", rather than properties I explicitly declared? I've tried `BindingFlags.DeclaredOnly`. – drzaus Jul 17 '12 at 15:43
  • **UPDATE** nevermind - I found that the method using this reflection (itself in an object extension) ended up calling itself with the converted result, so my extension was getting called on an object AND THEN on the resulting dictionary. – drzaus Jul 17 '12 at 15:54
  • I can't compile this in Unity3D, am I missing an assembly reference? – C0D3 Dec 10 '13 at 19:10
  • For other Unity3D users - add usings to top and remember the code returns System.Oject not unity objects. using System.Collections.Generic; using System.Linq; using System.Reflection; – Grant M May 21 '14 at 05:19
  • 2
    When I try this it returns Dictionary not Dictionary, and thus does not satisfy the OP. – Tim Williams Nov 21 '20 at 14:20
  • 1
    @TimWilliams Thank you, I've fixed the issue ;-) – Matías Fidemraizer Nov 24 '20 at 08:48
  • 1
    @TimWilliams did you miss the cast to string? – Hutch Moore Nov 24 '20 at 19:35
  • 1
    Although not all properties will cast to string, so perhaps it's better to do this: `prop => prop.GetValue(o, null)?.ToString() ?? ""` – John M Sep 23 '21 at 11:54
  • @JohnM Right. BTW, check the OP's question. I just answered to fit OP's requirements. – Matías Fidemraizer Oct 05 '21 at 20:53
26

Here a example with reflection without LINQ:

    Location local = new Location();
    local.city = "Lisbon";
    local.country = "Portugal";
    local.state = "None";

    PropertyInfo[] infos = local.GetType().GetProperties();

    Dictionary<string,string> dix = new Dictionary<string,string> ();

    foreach (PropertyInfo info in infos)
    {
        dix.Add(info.Name, info.GetValue(local, null).ToString());
    }

    foreach (string key in dix.Keys)
    {
        Console.WriteLine("nameProperty: {0}; value: {1}", key, dix[key]);
    }

    Console.Read();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bruno Costa
  • 2,708
  • 2
  • 17
  • 25
  • This saved me at least a days worth of work. Thanks so much I would vote you up twice if I could! – Kibitz503 Nov 29 '12 at 21:54
  • info.GetValue() may return null if the underlying property is null, so ToString() can throw an exception, might be worth to check the return value. – Jay May 05 '22 at 04:40
5
public static Dictionary<string, object> ToDictionary(object model)
    {
        var serializedModel = JsonModelSerializer.Serialize(model);
        return JsonModelSerializer.Deserialize<Dictionary<string, object>>(serializedModel);
    }

I have used the above code. As simplified as possible and it works without reflection and the model could be nested and still work. (Change your code to not use Newtonsoft if you are using Json.net)

dotnet-provoke
  • 1,308
  • 14
  • 25
  • I'd imagine this method to be far less efficient (and I'm certain JsonModelSerializer is using reflection internally... So it doesn't really work without reflection.) – R J Apr 05 '21 at 08:34
2

I would like to add an alternative to reflection, using JToken. You will need to check the benchmark difference between the two to see which has better performance.

var location = new Location() { City = "London" };
var locationToken = JToken.FromObject(location);
var locationObject = locationObject.Value<JObject>();
var locationPropertyList = locationObject.Properties()
    .Select(x => new KeyValuePair<string, string>(x.Name, x.Value.ToString()));

Note this method is best for a flat class structure.

Faesel Saeed
  • 199
  • 1
  • 15
1

Give this a try.

This uses reflection to retrieve the object type, then all of the properties of the supplied object (PropertyInfo prop in obj.GetType().GetProperties(), see https://learn.microsoft.com/en-us/dotnet/api/system.type.getproperties?view=netcore-3.1). It then adds the property name as a key in the dictionary and, if a value exists, it adds the value, otherwise it adds null.

    public static Dictionary<string, object> ObjectToDictionary(object obj)
    {
        Dictionary<string, object> ret = new Dictionary<string, object>();

        foreach (PropertyInfo prop in obj.GetType().GetProperties())
        {
            string propName = prop.Name;
            var val = obj.GetType().GetProperty(propName).GetValue(obj, null);
            if (val != null)
            {
                ret.Add(propName, val);
            }
            else
            {
                ret.Add(propName, null);
            }
        }

        return ret;
    }
joelc
  • 2,687
  • 5
  • 40
  • 60
0
protected string getExamTimeBlock(object dataItem)
{
    var dt = ((System.Collections.Specialized.StringDictionary)(dataItem));

    if (SPContext.Current.Web.CurrencyLocaleID == 1033) return dt["en"];
    else return dt["sv"];
}
Jon
  • 1,060
  • 8
  • 15
0

Just a gift for someone only need a simple and flat Dictionary<String,String> not requiring hierarchy or deserialize back to an object like me

    private static readonly IDictionary<string, string> SPECIAL_FILTER_DICT = new Dictionary<string, string>
    {
        { nameof(YourEntityClass.ComplexAndCostProperty), "Some display text instead"},
        { nameof(YourEntityClass.Base64Image), ""},
        //...
    };


    public static IDictionary<string, string> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
    {
        if (source == null)
            return new Dictionary<string, string> {
                {"",""}
            };

        return source.GetType().GetProperties(bindingAttr).ToDictionary
        (
            propInfo => propInfo.Name,
            propInfo => propInfo.GetValue(source, null).GetSafeStringValue(propInfo.Name)
        );
    }


    public static String GetSafeStringValue(this object obj, String fieldName)
    {
        if (obj == null)
            return "";

        if (obj is DateTime)
            return GetStringValue((DateTime)obj);

        // More specical convert...

        if (SPECIAL_FILTER_DICT.ContainsKey(fieldName))
            return SPECIAL_FILTER_DICT[fieldName];

        // Override ToString() method if needs
        return obj.ToString();
    }


    private static String GetStringValue(DateTime dateTime)
    {
        return dateTime.ToString("YOUR DATETIME FORMAT");
    }
Nguyen Minh Hien
  • 455
  • 7
  • 10
0

I hope this extension can be useful to someone.

public static class Ext {
    public static Dictionary<string, object> ToDict<T>(this T target)
        => target is null
            ? new Dictionary<string, object>()
            : typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
                        .ToDictionary(
                            x => x.Name,
                            x => x.GetValue(target)
                        );
}
Vas Mil
  • 605
  • 1
  • 8
  • 21
  • 1
    It works but I'd argue if this is an extension method abstracting the logic the syntax of this is over compressed and obscured by the language "sugar". In a scenario like this I'd leave the logic in it's more verbose format as it makes it much easier to read. – Oliver Aug 12 '20 at 16:20
  • An explanation would be in order. – Peter Mortensen Oct 06 '20 at 12:34
0
public static Dictionary<string, string> ObjectToDictionary(object obj)
{
    return Newtonsoft.Json.Linq.JObject.FromObject(obj).ToObject<Dictionary<string, string>>();
}
  • Thank you for your interest in contributing to the Stack Overflow community. This question already has quite a few answers—including one that has been extensively validated by the community. Are you certain your approach hasn’t been given previously? **If so, it would be useful to explain how your approach is different, under what circumstances your approach might be preferred, and/or why you think the previous answers aren’t sufficient.** Can you kindly [edit] your answer to offer an explanation? – Jeremy Caney Aug 14 '23 at 00:56