Coder Perfect

Reflection is used to get the value of a property from a string.

Problem

In my code, I’m attempting to create the Data transformation using the Reflection1 example.

I want to eliminate the types and properties from the GetSourceValue method and have GetSourceValue get the value of the property using simply a single string as the parameter. I’d like to pass a class and a property in a string and have the property’s value resolved.

Is this possible?

1 The original blog entry is archived on the web.

Asked by pedrofernandes

Solution #1

 public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }

Of course, you’ll want to add validation and other features, but that’s basically it.

Answered by Ed S.

Solution #2

Let’s see what we can come up with:

public static Object GetPropValue(this Object obj, String name) {
    foreach (String part in name.Split('.')) {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        PropertyInfo info = type.GetProperty(part);
        if (info == null) { return null; }

        obj = info.GetValue(obj, null);
    }
    return obj;
}

public static T GetPropValue<T>(this Object obj, String name) {
    Object retval = GetPropValue(obj, name);
    if (retval == null) { return default(T); }

    // throws InvalidCastException if types are incompatible
    return (T) retval;
}

This allows you to descend into properties with just a single string, such as this:

DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");

These methods can be used as static methods or extensions.

Answered by jheddings

Solution #3

To any Class, add:

public class Foo
{
    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }

    public string Bar { get; set; }
}

Then you can utilize it as follows:

Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];

Answered by Eduardo Cuomo

Solution #4

What about utilizing the Microsoft.VisualBasic namespace’s CallByName (Microsoft.VisualBasic.dll)? It gets attributes, fields, and methods of regular objects, COM objects, and even dynamic objects using reflection.

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

and then

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();

Answered by Fredou

Solution #5

jheddings provided an excellent response. PropertyName may be property1.property2[X].property3: I’d like to improve it by allowing referencing of aggregated arrays or collections of objects, so that propertyName could be property1.property2[X].property3:

    public static object GetPropertyValue(object srcobj, string propertyName)
    {
        if (srcobj == null)
            return null;

        object obj = srcobj;

        // Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
        string[] propertyNameParts = propertyName.Split('.');

        foreach (string propertyNamePart in propertyNameParts)
        {
            if (obj == null)    return null;

            // propertyNamePart could contain reference to specific 
            // element (by index) inside a collection
            if (!propertyNamePart.Contains("["))
            {
                PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart);
                if (pi == null) return null;
                obj = pi.GetValue(obj, null);
            }
            else
            {   // propertyNamePart is areference to specific element 
                // (by index) inside a collection
                // like AggregatedCollection[123]
                //   get collection name and element index
                int indexStart = propertyNamePart.IndexOf("[")+1;
                string collectionPropertyName = propertyNamePart.Substring(0, indexStart-1);
                int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length-indexStart-1));
                //   get collection object
                PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName);
                if (pi == null) return null;
                object unknownCollection = pi.GetValue(obj, null);
                //   try to process the collection as array
                if (unknownCollection.GetType().IsArray)
                {
                    object[] collectionAsArray = unknownCollection as object[];
                    obj = collectionAsArray[collectionElementIndex];
                }
                else
                {
                    //   try to process the collection as IList
                    System.Collections.IList collectionAsList = unknownCollection as System.Collections.IList;
                    if (collectionAsList != null)
                    {
                        obj = collectionAsList[collectionElementIndex];
                    }
                    else
                    {
                        // ??? Unsupported collection type
                    }
                }
            }
        }

        return obj;
    }

Answered by AlexD

Post is based on https://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection