Hi there to everyone. Today I want to talk about a fantastic technique that I think it will help you a lot in your daily programming tasks. This technique is called Static Reflection, here is a nice explanation about what it does:
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 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:
Let's say that we have a junior programmer who does have a very bad way of naming things in code, he likes to use TXTSpeak
a lot while writing 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 writes the following data structure:
public class PRSN
{
public int PRSNID { get; set; }
public string PRSNNM { get; set; }
}
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()
{
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 a 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 worse is that this kind of code is all over the place and you would have to go with the painful process of “search/replace” all over your code.
Is there a better way? Sure there is, here is where Static Reflection comes in.
With Static Reflection, all you have to do is to pass an Expression indicating which property 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 stuff happens 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 has been borrowed from another library (FluentNHibernate
) so I think it is better to have it in a separated class, and the StaticReflector
class 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, this 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 the 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; }
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 some tests 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 tests 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 looks 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.
If we accept this action, our code 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 series of unit tests so you could check in more depth how this works. To run them all from inside Visual Studio, you will need to have installed TestDriven .NET and configure XUnit as your test suite.
Hope you enjoyed the article.
Bye bye.
Shameless plug: You can check this article on my blog here.