Treat Object Like Dictionary of Properties in C#

16,962

Solution 1

I don't believe there is a built-in .Net type like this already in the .Net framework. It seems like you really want to create an object that behaves a lot like a Javascript object. If so then deriving from DynamicObject may be the right choice. It allows you to create an object which when wrapped with dynamic allows you to bind directly obj.Name or via the indexer obj["Name"].

public class PropertyBag : DynamicObject {
  private object _source;
  public PropertyBag(object source) {
    _source = source;
  }
  public object GetProperty(string name) {  
    var type = _source.GetType();
    var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    return property.GetValue(_source, null);
  }
  public override bool TryGetMember(GetMemberBinder binder, out object result) {
    result = GetProperty(binder.Name);
    return true;
  }
  public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
    result = GetProperty((string)indexes[0]);
    return true;
  }
}

You can use this to wrap any type and use both the indexer and name syntax to get the properties

var student = new Student() { FirstName = "John", LastName = "Doe" };
dynamic bag = new PropertyBag(student);
Console.WriteLine(bag["FirstName"]);  // Prints: John
Console.WriteLine(bag.FirstName);     // Prints: John

Solution 2

I have this extension method, probably the simplest it can get:

public static Dictionary<string, object> ToPropertyDictionary(this object obj)
{
    var dictionary = new Dictionary<string, object>();
    foreach (var propertyInfo in obj.GetType().GetProperties())
        if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0)
            dictionary[propertyInfo.Name] = propertyInfo.GetValue(obj, null);
    return dictionary;
}

Now you can do:

object person = new { Name = "Bob", Age = 45 };
var lookup = person.ToPropertyDictionary();
string name = (string)lookup["Name"];
lookup["Age"] = (int)lookup["Age"] + 1; // indeed editable

Note:

  1. that this dictionary is case-sensitive (you can trivially extend it passing the right StringComparer).

  2. that it ignores indexers (which are also properties) but it's up to you to work on it.

  3. that the method is not generic considering it doesn't help boxing because internally it calls obj.GetType, so it boxes anyway at that point.

  4. that you get only the "readable" properties (otherwise you dont get the values held in it). Since you want it to be "writable" as well then you should use CanWrite flag as well.

Solution 3

dynamic keyword may be one option for you. it uses dynamic language runtime. At runtime, it tries to match the closest available type in the program. If it cant, then it converts the dynamic type to dictionay object, where key is the name of property and value is the value of property.

follow these links of MSDN:

Using dynamic keyword in C#
dynamic (C# Reference)
DLR Overview
usage of dynamic sample walkthough page

Share:
16,962
Travis Parks
Author by

Travis Parks

I'm a developer who spends most of his time writing business applications in .NET. I especially enjoy computing theory, application design and good programming practices. I try to keep my skills up-to-date and keep my knowledge broad. I love creating open source projects; check me out on GitHub. I consider myself an expert at .NET, software design, automation and large-scale distributed enterprise architectures.

Updated on June 05, 2022

Comments

  • Travis Parks
    Travis Parks about 2 years

    I want to be able to access property values in an object like a dictionary, using the name of the property as a key. I don't really care if the values are returned as objects, so Dictionary<string, object> is fine. This is the intended usage:

    object person = new { Name: "Bob", Age: 45 };
    IDictionary<string, object> lookup = new PropertyDictionary(person);
    string name = (string)person["Name"];
    person["Age"] = (int)person["Age"] + 1; // potentially editable
    

    I was about to implement my own class for this, but then I started noticing classes like DynamicObject implement the IDictionary interface, which made think this was already being done for me somewhere.

    What I want is similar to the functionality used by ASP.NET MVC that allows using anonymous types to set HTML tag attributes. I have a lot of classes that use dictionaries as data sources, but most of the time I should be able to pass in objects as well.

    Since this is for a general-purpose library, I thought I would create a reusable class that simply decorated an object with the IDictionary interface. It will save me from creating an explosion of overloads.