Showing posts with label methods. Show all posts
Showing posts with label methods. Show all posts

Manipulating Properties and Methods with Reflection

Today I’m going to write about a simple yet powerful way to manipulate properties and methods of a given type. We’ll set values to properties and invoke methods through the use of reflection.

Maybe you haven’t had the chance to use reflection or maybe you even don’t know what is reflection.

Reflection is one of the most powerful features a programming language has as is the case of C# programming language that I’ll be using in this post.

In just one phrase extracted from Wikipedia we can define what is reflection:

Reflection is the process by which a computer program can observe and modify its own structure and behavior. The programming paradigm driven by reflection is called reflective programming.

Our objective is to manipulate the property value and methods of a type by means of reflection, that is, we’ll have access to these properties and methods by looking at the type’s metadata.

Let’s exemplify with a specific case that I came into while I was working on my first project at Chemtech: we had our ASP.NET solution divided into specific projects in what we call the MVP pattern. I suggest that you to read the post Model View Presenter pattern with Castle in ASP.NET to get a grasp of it.

In a given task I had 15 static textboxes inside an .aspx page (View) and I needed to set their values inside the Presenter. What is the best way to do it? Should you hardcode each and every textbox setting their values? It’s not an elegant solution. So how to get over it? Using reflection to get the type’s metadata. Let’s see how it is easy.

Let’s get to the code:

private void BindProperty(string viewPropertyName, object propertyValue)
{
    // Getting the property I want to use.
    PropertyInfo propertyInfo = typeof(IMyView).GetProperty(viewPropertyName);

    // Verifying if the property was acquired with success.
    if (propertyInfo != null && propertyInfo.CanWrite)
    {
        // Set the property value.
        propertyInfo.SetValue(view, propertyValue, null);
    }
}

Reflection allows us to make a generic piece of code, that is, with only one method we can set the value of all the textboxes.

The above method receives the property name as a parameter and we also pass to the method the value we want to assign to the property.

This same approach can be used with methods. Let’s see an example:

private void BindMethod(string viewMethodName, object[] methodParameters)
{
    // Getting the method I want to use.
    MethodInfo methodInfo = typeof(IMyView).GetMethod(viewMethodName);

    if (methodInfo !=null)
    {
// Call/Invoke the method with the desired parameters. methodInfo.Invoke(view, methodParameters); } }

Again we have a generic piece of code that can be used to call whatever method we want passing whatever parameters we want.

To use PropertyInfo and MethodInfo we declare the namespace System.Reflection.

We could make these methods even more generic by passing the view object (type) we want as a parameter. Bellow I show a class named ReflectionUtil with such modifications:

/// <summary>
/// Utility class for Reflection operations.
/// </summary>
public class ReflectionUtil
{
    /// <summary>
    /// Sets a value to a property through the use of Reflection.
    /// </summary>
    /// <param name="obj">Object that owns the property</param>
    /// <param name="propertyName">Property name</param>
    /// <param name="propertyValue">Value to be set</param>
    public static void BindProperty(object obj, string propertyName, object propertyValue)
    {
        // Getting the property I want to use.
        PropertyInfo propertyInfo = obj.GetType().GetProperty(propertyName);

        // Verifying if the property was acquired with success.
        if (propertyInfo != null && propertyInfo.CanWrite)
        {
            // Set the property value.
            propertyInfo.SetValue(obj, propertyValue, null);
        }
    }

    /// <summary>
    /// Calls a method through the use of Reflection.
    /// </summary>
    /// <param name="obj">Object that owns the method</param>
    /// <param name="methodName">Method name</param>
    /// <param name="methodParameters">Method parameters</param>
    public static void BindMethod(object obj, string methodName, object[] methodParameters)
    {
        // Getting the method I want to use.
        MethodInfo methodInfo = obj.GetType().GetMethod(methodName);

        if (methodInfo != null)
        {
// Call/Invoke the method with the desired parameters. methodInfo.Invoke(obj, methodParameters); } } }

OK. Now that we have the methods defined, let’s use them.

I’ll use the application I’ve shown in Model View Presenter pattern with Castle in ASP.NET as the base for this post.

IMyView interface declares the following members:

public interface IMyView : IBaseView
{
    event EventHandler FirstLoading;

    void MyMethod();

    string TextBox1Text { set; }
    string TextBox2Text { set; }
    string TextBox3Text { set; }
    string TextBox4Text { set; }
    string TextBox5Text { set; }
    string TextBox6Text { set; }
    string TextBox7Text { set; }
    string TextBox8Text { set; }
    string TextBox9Text { set; }
    string TextBox10Text { set; }

    void FillGridView1(List<object> values);
    void FillGridView2(List<object> values);
}

MyView implements what’s in IMyView interface:

public partial class MyView : Page, IMyView
{
    private MyPresenter presenter;

    .
.
.
#region Implementation of IMyView public event EventHandler FirstLoading; public void MyMethod() { Response.Write("Reflection power"); } #region TextBoxes public string TextBox1Text { set { TextBox1.Text = value; } } public string TextBox2Text { set { TextBox2.Text = value; } }

.
.
. #endregion #region Methods public void FillGridView1(List<object> values) { GridView1.DataSource = values; GridView1.DataBind(); } public void FillGridView2(List<object> values) { GridView2.DataSource = values; GridView2.DataBind(); } #endregion #endregion }

Inside the Presenter MyPresenter I implement the logic with the following:

/// <summary>
/// Specific FirstLoading implemented by each inheritor
/// </summary>
protected override void FirstLoading()
{
    view.MyMethod();

    // Useful technique to avoid calling 10 lines of code.
    for (int i = 1; i <= 10; i++)
    {
        ReflectionUtil.BindProperty(view, string.Format("TextBox{0}Text", i), (i * i).ToString());
    }

    // Useful technique to avoid writing methods almost identical just to change a method call.
    for (int i = 1; i <= 2; i++)
    {
        // Do some common logic here...

        // Call a specific method with Reflection.
ReflectionUtil.BindMethod(view, string.Format("FillGridView{0}", i), new object[] { new List<object> { i * 2, i * 3, i * 4, i * 5 } }); // Do some common logic here... } }

When we run the web app, we get the following result:

Reflection result

I covered just a simple use case of reflection in this post but it’s useful in our day to day job.

The technique implemented in this post allows us to write clean and generic code. I have already used it in another project which allowed me to write as few lines of code as possible. Let’s say it decreased from 250 sloc to 25 sloc. A reduction of 10 times sloc.

Last note
I read the article Survival of the Fittest: Natural Selection with Windows Forms on MSDN Magazine when I was on the 9th period of the Computer Engineering course studying Artificial Intelligence. From this moment on I started to visualize the importance of reflection and how powerful it is. The referenced article discusses about Genetic Algorithms and the author’s sample code makes extensive use of reflection. Great read if you’re interested enough! Oh, I even translated this article to Portuguese at that time. I want to put it online so that others can benefit from it. :o)

Visual Studio 2010 C# ASP.NET Web Application
You can get the Microsoft Visual Studio Project at:

http://sites.google.com/site/leniel/blog/ReflectionWebApp.zip

To try out the code you can use the free Microsoft Visual Web Developer 2010 Express Edition that you can get at: http://www.microsoft.com/express/Web/