3

I have a class with some setters and getters called Customer which holds some string values. I then create a List and add many of the Customer class to it. How do i then access the getter and setter methods using reflection?

List<Customer> Customers; // assume we have filled it
Customers[0].Name; // how do I use reflection to call this from a string?

Also the Customer class, Customers and the Name method are all public.

I am in a situation where I need to dynamically get the value from the class based on the column the user is trying to edit. The column name is the name of the method I need to call.

I have looked into the GetType().GetMethod() and my question is how to use it with a list like I have above.

An example would solve my problem.

stackdaddy
  • 111
  • 1
  • 10
  • 3
    Not sure what you're trying to do here... – It'sNotALie. May 31 '13 at 21:05
  • 5
    Why reflection? So you have `Name` and you want to access the `Name` property, you have `Number` and you want to access the `Number` property. Why do you need this inefficient and error-prone approach? – Tim Schmelter May 31 '13 at 21:06
  • PropertyInfo.GetValue http://msdn.microsoft.com/en-us/library/hh194385.aspx – bmm6o May 31 '13 at 23:21
  • 1
    *"my question is how to use it with a list like I have above."* A `List<>` is just a container. – user Jun 01 '13 at 12:45

4 Answers4

2

UPDATE: There is a nice post which explains how to and provides code for accessing methods or properties with refactor safe code. http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/


All the given answers will work. However, none are refactor safe. I thought I'd offer a solution that a bit more refactor safe.

//Create a dictionary of columnName => property info using the GetPropertyInfo method.
public static IDictionary<string, PropertyInfo> propertyInfos = new Dictionary<string, PropertyInfo>
    {
        {"Name", GetPropertyInfo((Customer c) => c.Name) }
    };

List<Customer> Customers= new List<Customer> { new Customer { Name = "Peter Pan" } };
Customer customer = Customers[0];
string column = "Name";
PropertyInfo propertyInfo = propertyInfos[column];
//Set property
propertyInfo.SetValue(customer, "Captain Hook", null);
//Get property -- Returns Captain Hook
object propertyValue = propertyInfo.GetValue(customer, null);

I've taken GetPropertyInfo from this answer. I slightly modified it by removing the source parameter because you can see by HappyNomad's comment that it's not necessary for the newest version of C#.

public static PropertyInfo GetPropertyInfo<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
{
    Type type = typeof(TSource);

    MemberExpression member = propertyLambda.Body as MemberExpression;
    if (member == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a method, not a property.",
            propertyLambda.ToString()));

    PropertyInfo propInfo = member.Member as PropertyInfo;
    if (propInfo == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a field, not a property.",
            propertyLambda.ToString()));

    if (type != propInfo.ReflectedType &&
        !type.IsSubclassOf(propInfo.ReflectedType))
        throw new ArgumentException(string.Format(
            "Expresion '{0}' refers to a property that is not from type {1}.",
            propertyLambda.ToString(),
            type));

    return propInfo;
}

My suggestion is a bit more refactor safe because you'll hit a compile time error every time you change the Name property on Customer.

Side note: I agree with Tim S.. You'll likely be able to find a safer and more performant way than reflection :).

Community
  • 1
  • 1
Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
1

It depends where the "dynamic" part of your question starts. Do you need to access the List itself dynamically? If so, then you have two dynamic (reflection) calls to make. However, if you have access to the List directly, and you can use the indexer to find the right customer, and only then do you need to use a reflection call, then your code will look something like:

var fieldName = "Name";
var customer = Customers[x];
Type type = typeof(Customer);
var prop = type.GetProperties().Single(field => field.Name == fieldName);

// once you have your propinfo + your reference to the right customer, just call...
Object value = prop.GetValue(customer, null); // you'll need to cast/convert away from object

See Query a collection using PropertyInfo object in LINQ for more details

Community
  • 1
  • 1
Eli Gassert
  • 9,745
  • 3
  • 30
  • 39
  • I don't have any way of knowing the index and column without a great deal of code, I intentional kept my example simple to get the exact answer I wanted although yours works as well and is a good lambada expression example which I am also unfamiliar with. – stackdaddy Jun 03 '13 at 11:33
1

This example should get you started:

var namePropertyInfo = typeof(Customer).GetProperty("Name");
var name = namePropertyInfo.GetValue(Customers[0], null);

Now, name is an instance of object with value equal to Customer[0].Name. Proceed accordingly.

Matt Ellen
  • 11,268
  • 4
  • 68
  • 90
jason
  • 236,483
  • 35
  • 423
  • 525
  • This is exactly what I was looking for I guess I just had the syntax wrong but this is exactly what I need. – stackdaddy Jun 03 '13 at 11:24
1

Here's the answer to just what you're asking:

void Main()
{
    List<Customer> Customers= new List<Customer> { new Customer { Name = "John Smith" } };
    GetProp(Customers[0], "Name"); // "John Smith"
    SetProp(Customers[0], "Name", "Joe");
    GetProp(Customers[0], "Name"); // "Joe"
}
object GetProp(Customer customer, string propertyName)
{
    var property = typeof(Customer).GetProperty(propertyName);
    return property.GetValue(customer);
}
void SetProp(Customer customer, string propertyName, object propertyValue)
{
    var property = typeof(Customer).GetProperty(propertyName);
    property.SetValue(customer, propertyValue);
}

Or working on a not-strongly-typed list:

void Main()
{
    List<Customer> Customers= new List<Customer> { new Customer { Name = "John Smith" } };
    string name = (string)GetProp(Customers, 0, "Name"); // name == "John Smith"
}
object GetProp(object customerList, int index, string propertyName)
{
    var custList = (IList)customerList;
    var customer = custList[index];
    var nameProperty = customer.GetType().GetProperty(propertyName);
    return nameProperty.GetValue(customer);
}

And here's what I think you should really do: do not use reflection as part of modifying values in a table/grid, and not based on the column name (display value and property name aren't always the same). What should you do? That depends on what framework you're working with: WPF? ASP.NET web site? WinForms?

Tim S.
  • 55,448
  • 7
  • 96
  • 122
  • I may consider this code later on and appreciate the comments as well since I have never really used reflection before. I am not using reflection to modify data in any way only to retrieve it in some parts of my modified ListView. – stackdaddy Jun 03 '13 at 11:29