Title: Use reflection to list a class's properties in C#
This post begins a short series on using reflection. The tools that make C# work (such as the .NET Framework and the compiler that turns C# into IL code) use techniques that require them to learn a lot about the classes (and other things such as struct and enum) that go into a program. To make that possible, the whole system instruments classes so they know a lot about themselves. You can use those same reflection tools to query a class's type to learn about it.
Reflection lets you discover such things as the properties, fields, methods, and events that a class provides. It also lets you learn other information about those items such as their data types, accessibility (public, private), and attributes. It lets you learn about your own classes and even classes that are pre-defined in the .NET Framework or in other libraries. It even lets you examine base classes. For example, a Windows Forms program usually has a Form1 class that inherits from the System.Windows.Form class. Reflection lets you see any properties, methods, and events that you added to the Form1 class, in addition to properties, methods, and events inherited from the Form class.
Often you don't need to use reflection. If you're writing the code, you know what you put into it. Even when you're using a class that you didn't write, such as a .NET Framework class, you can often use the documentation and IntelliSense to figure out how to use it. Sometimes, however, reflection can be useful for learning about undocumented features. I have used it occasionally to see what's inside libraries that I've been working with that didn't come with good documentation.
This example shows how to list a class's properties. The example includes a lot of code dealing with displaying values in a ListView control. The following discussion omits that code and only shows the code that deals with reflection. Download the example program to see all the rest of the details.
To make using reflection easier, the form's code starts with the following using directive.
using System.Reflection;
This example uses reflection to examine the Form1 class. To make it a bit easier to see the effects of different kinds of property declarations, the program uses the following code to add several properties to the class.
// Add some properties.
private int _MyPrivateProperty;
private int MyPrivateProperty
{
get { return _MyPrivateProperty; }
set { _MyPrivateProperty = value; }
}
public int MyPublicProperty
{
get { return 2; }
set { }
}
public static int MyPublicStaticProperty
{
get { return 3; }
}
protected int MyProtectedProperty
{
get { return 4; }
}
public virtual int MyPublicVirtualProperty
{
set { }
}
All of the properties' names begin with My so they all appear together in the program's display.
This code defines:
- A private property with a typical backing variable.
- A public property that always returns the value 2.
- A public read-only static property.
- A protected read-only property.
- A public virtual property.
When the form loads, the following code executes to display information about the Form1 class's properties including those defined by the previous code. (The ListViewMakeRow method just displays values in the program's ListView control. It doesn't really have anything to do with reflection so you can ignore it for now.)
// List the properties.
// Use the class you want to study instead of Form1.
object property_value;
PropertyInfo[] property_infos = typeof(Form1).GetProperties(
BindingFlags.FlattenHierarchy |
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Static);
foreach (PropertyInfo info in property_infos)
{
string name = info.Name;
string attributes = info.PropertyType.Attributes.ToString();
if (info.CanRead) attributes += " get";
if (info.CanWrite) attributes += " set";
string value = "";
// See if it's an array.
if (!info.PropertyType.IsArray)
{
// It's not an array.
if (info.CanRead) property_value = info.GetValue(this, null);
else property_value = "---";
if (property_value == null)
value = "<null>";
else
value = property_value.ToString();
}
else
{
// It is an array.
name += "[]";
value = "<array>";
}
ListViewMakeRow(lvwProperties, name,
info.PropertyType.ToString(),
attributes, value);
}
The code starts by using typeof(Form1) to get a System.Type object representing the Form1 class. It calls that object's GetProperties method to get information about the properties defiend by the class. It passes GetProperties values to indicate what information it should return. The BindingFlag values that this code uses are:
- FlattenHierarchy - Return information about properties that are inherited from parent classes
- Instance - Return information about instance (non-static) properties
- NonPublic - Return information about non-public properties
- Public - Return information about public properties
- Static - Return information about static properties
The code loops through the PropertyInfo objects returned by GetProperties. It uses the following PropertyInfo properties:
- Name - Gives the property's name
- PropertyType.Attributes - Gives information about the property's attributes
- CanRead - True if the property is readable
- CanWrite - True if the property is writable
Next, the code tries to get the property's value. This can be somewhat tricky depending on the property's data type and whether it is an array.
If the PropertyType.IsArray property indicates the property is not an array, the code uses CanRead to see if it can read the value. If the program can read the value, it uses the PropertyInfo object's GetValue method to get the value for the current form object (this). If the program cannot read the value, it displays the value ---.
If the program got a property value object and that object is not null, the code calls its ToString method to convert it into a string and displays the result.
If the IsArray method indicates that the property is an array, the code adds brackets around the property's name and displays its value as <array>.
Finally, the call to ListViewMakeRow displays the property's information in the program's ListView control. Download the example program to see how that works.
Download the example to experiment with it and to see additional details.
|