I'm trying to access various parts of a nested class structure using a arbitrary string.
Given the following (contrived) classes:
public class Person
{
public Address PersonsAddress { get; set; }
}
public class Adddress
{
public PhoneNumber HousePhone { get; set; }
}
public class PhoneNumber
{
public string Number { get; set; }
}
I'd like to be able to get the object at "PersonsAddress.HousePhone.Number"
from an instance of the Person
object.
Currently I'm doing some funky recursive lookup using reflection, but I'm hoping that some ninjas out there have some better ideas.
For reference, here is the (crappy) method I've developed:
private static object ObjectFromString(object basePoint, IEnumerable<string> pathToSearch)
{
var numberOfPaths = pathToSearch.Count();
if (numberOfPaths == 0)
return null;
var type = basePoint.GetType();
var properties = type.GetProperties();
var currentPath = pathToSearch.First();
var propertyInfo = properties.FirstOrDefault(prop => prop.Name == currentPath);
if (propertyInfo == null)
return null;
var property = propertyInfo.GetValue(basePoint, null);
if (numberOfPaths == 1)
return property;
return ObjectFromString(property, pathToSearch.Skip(1));
}
Since you are already interested in resolving string property paths, you may benefit from looking into the Dynamic LINQ query library posted as an example by Scott Guthrie @ Microsoft. It parses your string expressions and produces express trees that can be compiled and cached as suggested by @Brian Dishaw.
This would provide you with a wealth of additional options by providing a simple and robust expression syntax you can use in your configuration approach. It supports the common LINQ methods on enumerables, plus simple operator logic, math calculations, property path evaluation, etc.
I've had to some something similar in the past. I went with the lambda approach because after compiling them I can cache them. I've removed the caching in this code.
I included a few unit tests to show the usage of the method. I hope this is helpful.
Here's a non-recursive version with (almost) the same semantics:
You could simply use the standard .NET DataBinder.Eval Method, like this: