Click here to Skip to main content
6,929,899 members and growing! (26,605 online)
Email Password   helpLost your password?
    Beginner License: The Code Project Open License (CPOL)

Getting Fun with .Net Static Reflection

By emiaj

How the usage of Static Reflection could help in the refactoring process.
C# (C#3.0), .NET
Revision:8 (See All)
Posted:13 May 2009
Updated:2 Jul 2009
Views:9,421
Bookmarked:31 times
Technical Blog
printPrint Friendly   add Share
      Discuss Discuss   Broken Article?Report  
9 votes for this technical blog.
Popularity: 3.82 Rating: 4.00 out of 5

1

2
2 votes, 22.2%
3
5 votes, 55.6%
4
2 votes, 22.2%
5

Hi there to everyone. Today I want to talk about a fantastic technique that I think it will help you dear reader a lot in your daily programming task.
This technique is called Static Reflection, here is a nice explanation about what it does from http://www.lostechies.com/blogs/gabrielschenker/archive/2009/02/03/dynamic-reflection-versus-static-reflection.aspx:

Static Reflection gathers meta information through the inspection of the Expression Tree.

Thanks to this, you do not need any magic string to interrogate a given type for their properties or methods (like with Dynamic Reflection happens).

One of the benefits that you could get from this technique is to create highly “refactorable” (is that a word?) projects due to the elimination of magic strings.

Let me show you an example about this scenario:

Lets say that we have a junior programmer who does have a very bad way of name things in code, he likes a lot to use TXTSpeak while writes code.
So one day we ask him to write a tiny windows app which should load in a dropdown a list of persons, and he goes ahead and write the following data structure:

    public class PRSN //"Person" = PRSN in TXTSpeak
    {
        public int PRSNID { get; set; } //"PersonID" = PRSNID in TXTSpeak
        public string PRSNNM { get; set; } //"PersonName" = PRSNNM in TXTSpeak
    }   

And his winform client would look like:

     public partial class Form1 : Form
    {
 
        public Form1()
        {
            fillList();
            InitializeComponent();
        }
 
        private List<PRSN> dropdownDataSource = new List<PRSN>();
 
        private void fillList()
        {
            // in the real world here you should call to the database 
            // to retrieve this data
            // for the sake of the demo just use the following
 
            dropdownDataSource.Add(new PRSN()
            {
                PRSNID = 1,
                PRSNNM = "Jaime"
            });
            dropdownDataSource.Add(new PRSN()
            {
                PRSNID = 2,
                PRSNNM = "John"
            });
 
            dropdownDataSource.Add(new PRSN()
            {
                PRSNID = 3,
                PRSNNM = "Charles"
            });
 
            dropdownDataSource.Add(new PRSN()
            {
                PRSNID = 3,
                PRSNNM = "Mark"
            });
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            cboPersons.ValueMember = "PRSNID";
            cboPersons.DisplayMember = "PRSNNM";
            cboPersons.DataSource = dropdownDataSource;
        }
    }  

Here is the thing, please take a look at how the ValueMember and DisplayMember properties are being configured, the original programmer used just simple string to point to the name of the properties in his data structure. Now, your manager assigns you a task to clean up this mess and replace all that TXTSpeak with proper names, what is worst is that this kind of code is all over the place and you would have to go with the pain process of “search/replace” all over your code.  

Is there a better way? Sure it is, here is when it comes Static Reflection.

With Static Reflection all you have to do is to pass an Expression indicating which property do you want to inspect and that will give you a PropertyInfo object from where you can ask for the Name property of such instance and do the very same thing… but better :).

First of all let me explain how this works. In the project attached to this article you’ll find the following structure: 

 

The project where all the interesting happens are is the EmiajNet.StaticReflection.Library, in there you are going to find the ReflectionHelper and StaticReflector static classes. Both of them have methods related to static reflection, but why two?, well, the ReflectionHelper class it has been borrowed from another library (FluentNHibernate) so I think is better to have it in a separated class, and the StaticReflector class it has been created by me to fill some functionality that the ReflectionHelper class does not provide (static reflection over methods that return void).

Here is a class diagram to illustrate how those classes look like:


The basic idea of all of them is to inspect the expression being passed and extract the object that is related to the signature of the method. So the GetMethod method returns a MethodInfo, the GetProperty method returns a PropertyInfo and so on.

This is how some of those methods look like:

ReflectionHelper

        public static MethodInfo GetMethod<T>(Expression<Func<T, object>> expression)
        {
            MethodCallExpression methodCall = (MethodCallExpression) expression.Body;
            return methodCall.Method;
        }

        public static PropertyInfo GetProperty<MODEL>(Expression<Func<MODEL, object>> expression) 
        { 
            return (PropertyInfo) GetMember(expression);
        } 

        public static MemberInfo GetMember<MODEL>(Expression<Func<MODEL, object>> expression)
        { 
            MemberExpression memberExpression = getMemberExpression(expression);
            return memberExpression.Member; 
        } 

        public static FieldInfo GetField<MODEL>(Expression<Func<MODEL, object>> expression)
        { 
            return (FieldInfo)GetMember(expression);
        } 

StaticReflector:

        public static MethodInfo GetMethod<MODEL>(Expression<Func<MODEL, Action>> exp)
        {
            return GetMethodFromLambda(exp);
        }

        private static MethodInfo GetMethodFromLambda(LambdaExpression exp)
        {
            var unaryExp = (UnaryExpression)exp.Body;

            var methodCallExp = (MethodCallExpression)unaryExp.Operand;

            var constantExp = (ConstantExpression)methodCallExp.Arguments[2];

            MethodInfo output = (MethodInfo)constantExp.Value;

            return output;
        }

As you can see, is very straightforward, you can dig more into the library to give a more detailed idea.

Here are some examples from the EmiajNet.StaticReflection.Test project that I want to show you so you could realize how this works :

We have the following class that is subject of inspection: 

        private class TestClass
        {
            public int SomeIntMember;
            public string SomeStringMember;
            public TestClass SomeComplexMember;
            public string SomeStringProperty { get; set; }
            public int SomeIntProperty { get; set; }

            //indexed property
            public object this[int index]
            {
                get
                {
                    return null;
                }
            }

            public TestClass SomeComplexProperty { get; set; }

            public void SomeParameterlessMethod()
            {
            }
            public void SomeMethod(object x)
            {
            }
            public TestClass SomeParameterlessMethodWithReturnValue()
            {
                return null;
            }

            public TestClass SomeMethodWithReturnValue(object x)
            {
                return null;
            }
        }

And here are a some test that I throw at it:

        [Fact()] 
        public void TestStringProperty()
        {
            string expected = "SomeStringProperty";
            string propertyName = ReflectionHelper.GetProperty<TestClass>(x => x.SomeStringProperty).Name;
            Assert.Equal(expected, propertyName);
        }

        [Fact()]
        public void TestFunction()
        {
            string expected = "SomeMethodWithReturnValue";
            string methodName = ReflectionHelper.GetMethod<TestClass>(x => x.SomeMethodWithReturnValue(null)).Name;
            Assert.Equal(expected, methodName);
        }

        [Fact()] 
        public void TestMethod()
        {
            string expected = "SomeMethod";
            string methodName = StaticReflector.GetMethod<TestClass, object>(x => x.SomeMethod).Name;
            Assert.Equal(expected, methodName);
        }
 

As you can see, those test verify that the name of the expressions being evaluated are correct. Remember all of this is only to obtain information about the expression being inspected.

Now, continuing with the scenario that we talk about earlier, here is how this sample look like using Static Reflection:

        private void Form1_Load(object sender, EventArgs e)
        {
            cboPersons.ValueMember = ReflectionHelper.GetProperty<PRSN>(x => x.PRSNID).Name;
            cboPersons.DisplayMember = ReflectionHelper.GetProperty<PRSN>(x => x.PRSNNM).Name;
            cboPersons.DataSource = dropdownDataSource;
        } 

Isn’t this something more refactor friendly?, I mean, now you just should go and rename the class and its properties correctly and with the help of Visual Studio every occurrence of the affected properties is going to be changed automatically.

Refactor_Rename_Property

If we accept this action, our code it will be updated automatically and the application will continue working as usual:

        private void Form1_Load(object sender, EventArgs e)
        {
            cboPersons.ValueMember = ReflectionHelper.GetProperty<PRSN>(x => x.PersonID).Name;
            cboPersons.DisplayMember = ReflectionHelper.GetProperty<PRSN>(x => x.PRSNNM).Name;
            cboPersons.DataSource = dropdownDataSource;
        } 

Now you could continue refactoring the class name to Person and the other property to PersonName.

You can download the sample code to play around from here. There is a serie of unit tests so you could check in more deep how this works, to run them all from inside Visual Studio you will need to have installed TestDriven .Net and configure XUnit as you test suite.

Hope you had enjoyed the article. 

Bye bye.

Shameless plug: You can check this article on my blog here

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

emiaj


Member

Occupation: Web Developer
Location: Peru Peru

Other popular C# articles:

 
Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 11 of 11 (Total in Forum: 11) (Refresh)FirstPrevNext
GeneralInfoOf Pinmemberemiaj6:51 30 Jun '09  
GeneralRe: InfoOf - Bad News Pinassociateemiaj8:15 6 Jul '09  
Generali wonder... Pinmembercs_dilo4:41 30 Jun '09  
GeneralRe: i wonder... Pinmemberemiaj6:44 30 Jun '09  
GeneralRe: i wonder... Pinmembercs_dilo7:17 30 Jun '09  
GeneralRe: i wonder... [modified] Pinmemberemiaj8:49 30 Jun '09  
GeneralCould this easily convert identifiers to expanded forms? Pinmembersupercat919:26 24 Jun '09  
GeneralRe: Could this easily convert identifiers to expanded forms? [modified] Pinmemberemiaj4:12 25 Jun '09  
GeneralRe: Could this easily convert identifiers to expanded forms? Pinmembersupercat96:58 25 Jun '09  
GeneralRe: Could this easily convert identifiers to expanded forms? Pinmemberemiaj7:36 25 Jun '09  
Generali kown you mean but i don't kown what i to do Pinmemberzzx_12345617:44 24 Jun '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+PgUp/PgDown to switch pages.

PermaLink | Privacy | Terms of Use
Last Updated: 2 Jul 2009
Editor:
Copyright 2009 by emiaj
Everything else Copyright © CodeProject, 1999-2010
Web09 | Advertise on the Code Project