Yesterday I was working on a project and I needed a way to get the value of a property from an object based on a given path. For example, if we had the following setup

class Object1
{
       public int Id { get; set; }
       public string Name { get; set; }
       public Object2 SubObject { get; set; }
}
class Object2
{
      public int Id { get; set; }
      public string FirstName { get; set; }
      public string LastName { get; set; }
      public WhatEver SubSubObject { get; set; }
}
class WhatEver
{
      public string Name { get; set; }
}  

And we’ve instatiated an instance of Object1 like

var obj = new Object1()
 {
       Id = 10,
       Name = "Tester McTesting",
       SubObject = new Object2()
       {
           Id = 11,
           FirstName = "Tester",
           LastName = "#2",
          SubSubObject = new WhatEver() { Name = "Just another test" }
      }
 };

Now if we wanted to get the value of ‘Obj.SubObject.SubSubObject.Name’ we could easily do so in code and be done. But the project I was working on required that the path to the property is given as a string from a config file. So obviously I would need to use reflection or something similar to obtain the required value. There are at least 3 ways I can think of to do this.

  1. DataBinder.Eval()
  2. XML (XPath or Linq)
  3. Reflection

DataBinder.Eval() would have been a good choice because the project was an ASP.NET project. But, DataBinder.Eval() can’t handle lists. The Entities I was working with were lists.

  string value = DataBinder.Eval(“Obj.SubObject.SubSubObject.Name”);

XML would have been the best choice if arrays/lists weren’t involved.  XPath would have made it very simple to do the job if it were a simple object as we created above.

Reflection was best choice but it too has it’s limitations. You cannot specify a path and you have to handle arrays. In my scenario when it came to arrays/lists, I was defaulting to selecting the first index and continuing down the path. To handle the path I used a foreach() loop.

private string GetValueFromObject(T obj, string propertyPath) where T : class
   {
      Type type = obj.GetType();
      PropertyInfo prop = null;

      string[] parts = propertyPath.Split('.');
      object value = obj;

      foreach (string part in parts)
      {
          prop = type.GetProperty(part);
          var x = prop.GetValue(value, null);

          if (x is IList)
          {
              value = (x as IList)[0];
              type = value.GetType();
              continue;
          }
          else
              type = prop.GetType();

         value = prop.GetValue(value, null);
     }  
     return value.ToString();
 }

This might seem like an odd way of doing it, but it fit my needs and it worked to accomplish what I wanted. With this method I was able to load an Entity from Entity Framework and the paths from the config file and acquire the values for processing.

Advertisements