Tuesday, January 6, 2009

SetValue/GetValue

Occasionally you will run into a situation where you want to reference the property of an object by its name instead of directly accessing the property. Using the SetValue and GetValue functions you can actually access a property where the property name is stored in a string. Let’s start with a simple object to demonstrate this

public class Test
{
 private string name;

 public string Name
 {
 get { return name; }
 set { name = value; }
 }
}

Next you will need to import the Reflection namespace:

using System.Reflection;

Finally here is the code that will write and then read back the Name property:
Test testObj = new Test();
PropertyInfo pi = testObj.GetType().GetProperty("Name");
pi.SetValue(testObj, "Dan", null);
Console.WriteLine(pi.GetValue(testObj, null));

We start out by creating an instance of the Test object and then use the GetProperty function to get the PropertyInfo for the property “Name”. Property info allows you to access various information about a property and also provides access to the GetValue and SetValue functions. If the property can’t be found, GetProperty will return a null, so if there is any chance that the property name you are trying to access may not exist you would want to check if pi is null and handle that error appropriately.

Now that we have the PropertyInfo for the Name property we can write to it with SetValue. SetValue takes three parameters. The first is the object whose property we want to set, in this case the test object. The second parameter is the value we want to set the property to. The third is use for indexed properties which we will talk about next, for this example we will set that null.
Reading the value back is just as easy, we just call the GetValue function. Like SetValue, GetValue takes the object to get the property from as the first parameter, and the index as the second, again null in this example.

As I mentioned you can also use SetValue/GetValue to access an indexed property. Here is another sample object to work with:

public class Test
{
 private int[] num = new int[5];

 public int this[int index] 
 {
 get { return num[index]; }
 set { num[index] = value; }
 }
}

The code to read and write this property would look like this:

pi = testObj.GetType().GetProperty("Item");
pi.SetValue(testObj, 1, new object[] { (int)1 });
Console.WriteLine (pi.GetValue(testObj, new object[] { (int)1 }));

There are a couple differences to note here. First, in C# the default property of an object is the only one that can be indexed, that’s why the test object declares the property name as ‘this’. By default the name of the default property is ‘Item’ so that is what we pass to the GetProperty function. If you want you can change the name of this property by putting the following attribute before the property declaration in the object:

[IndexerNameAttribute("IndexedInstanceProperty")]

This will change the name of the property from Item to IndexedInstanceProperty. Note that you will have to import the System.Runtime.CompilerServices namespace to us this attribute.
The second difference is the index property that is passed to the SetValue and GetValue functions. This parameter is an array of objects. In this example we are using a static index of 1 but it takes a little extra code to turn this single value into an array.

You are probably not going to use SetValue and GetValue a lot but there are definitely situations where it really comes in handy.

No comments: