A problem I’ve encountered a number of times when writing tests for C# code is that I need the name of a property or method so that I can invoke it through reflection in the tester. It is easy to get a property name through reflection:
public class Sample
{
public static int Foo { get; set; }
}
[TestFixture]
public class When_asked_to_get_the_name_of_a_Property
{
[Test]
public void Should_be_able_to_get_the_name_using_reflection()
{
string name = typeof(Sample).GetProperty("Foo").Name;
Assert.AreEqual("Foo", name);
}
The problem is that if you rename the property you won’t discover that the code is now broken (due to the property name in the string being passed to GetProperty) until you run it. This makes for brittle tests. Another place one might want to avoid magic strings is in numerous places where the framework wants to take the name of a property to which to bind in order to fill a DataGrid, DropDownList, ArgumentException, etc:
private void BindData()
{
ddlState.DataSource = stateList;
ddlState.DataTextValue = "Name";
ddlState.DataFieldValue = "Code";
ddlState.DataBind();
}
As I haven’t seen a solution for this particular problem anywhere else I’m posting mine here. I use a feature of C# 3.5 and Linq to get the property name dynamically. First create an anonymous delegate to the property and save that as an Expression. Then drill into that expression to get the property name:
[Test]
public void Should_be_able_to_get_the_name_using_an_Expression()
{
Expression<Func<int>> expression = () => Sample.Foo;
MemberExpression body = (MemberExpression)expression.Body;
string name = body.Member.Name;
Assert.AreEqual("Foo", name);
}
Next refactor out a reusable method:
[Test]
public void Should_be_able_to_get_the_name_using_an_Expression()
{
string name = ReflectionUtility.GetPropertyName(() => Sample.Foo);
Assert.AreEqual("Foo", name);
}
}
public static class ReflectionUtility
{
public static string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression body = (MemberExpression) expression.Body;
return body.Member.Name;
}
}
This solution suffers somewhat from being obscure in intent due to the lambda, a drawback I try to alleviate with a good method name. So far so good but the code gets a bit uglier when you start working with instance properties instead of static ones because you have to have an instance before you can wrap a lambda around the instance property:
public class Sample2
{
public int Foo { get; set; }
}
[Test]
public void Should_be_able_to_get_the_name_using_an_Expression()
{
const Sample2 sample = null;
string name = ReflectionUtility.GetPropertyName(() => sample.Foo);
Assert.AreEqual("Foo", name);
}
If there is no instance handy, however, this clutters the code so how about just using the default:
[Test]
public void Should_be_able_to_get_the_name_using_an_Expression()
{
string name = ReflectionUtility.GetPropertyName(() => default(Sample2).Foo);
Assert.AreEqual("Foo", name);
}
Unfortunately ReSharper now warns that default(Sample2) could be null. I could add comments to make ReSharper ignore the potential null reference exception here but then we’re back to ugly code again. If another method is added to the reflection utility, however:
public static string GetPropertyName<T, TReturn>(Expression<Func<T, TReturn>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return body.Member.Name;
}
Resharper’s null reference exception warning can be eliminated:
[Test]
public void Should_be_able_to_get_the_name_using_an_Expression()
{
string name = ReflectionUtility.GetPropertyName((Sample2 s) => s.Foo);
Assert.AreEqual("Foo", name);
}
This solution still isn’t particularly obvious in intent but at least we can do it all on one line without any magic strings or objects that only exist to provide access to the instance property.
Other lines of research… How about an extension method:
public static class Extensions
{
public static string GetPropertyName<T,TReturn>(this Expression<Func<T,TReturn>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return body.Member.Name;
}
}
[Test]
public void Should_be_able_to_get_the_name_using_an_Extension()
{
string name = ((Expression<Func<Sample2,int>>)(s => s.Foo)).GetPropertyName();
Assert.AreEqual("Foo", name);
}
It works but … is really ugly. I prefer the (Sample2 s) => s.Foo implementation and it looks OK when you only have it here and there in your code but a bunch in a single place really starts to obfuscate the code. So how about encapsulating the ugly part:
public class Sample2
{
public static class BoundPropertyNames
{
// Resharper can collapse the following to a single visual line if so configured
public static string Foo
{
get
{
return ReflectionUtility.GetPropertyName((Sample2 s) => s.Foo);
}
}
}
public int Foo { get; set; }
// more properties ...
}
[Test]
public void Should_be_able_to_get_the_name_using_BoundPropertyNames()
{
string name = Sample2.BoundPropertyNames.Foo;
Assert.AreEqual("Foo", name);
}
Nifty! And as a bonus the compiler can probably boil it all down to a const… since we can boil it down to a readonly string if we really want to… check this out:
public class Sample2
{
public static class BoundPropertyNames
{
public static readonly string Foo = ((MemberExpression)((Expression<Func<Sample2, int>>)(s => s.Foo)).Body).Member.Name;
}
public int Foo { get; set; }
}
The code for doing the same for a method is quite a bit simpler because we can get the method name from a Func directly (ignoring the limitation of getting an instance already discussed above because we usually have one):
public class Sample3
{
public int Bar()
{
return 1;
}
}
[TestFixture]
public class When_asked_to_get_the_name_of_a_Method
{
[Test]
public void Should_be_able_to_get_the_name_using_a_Func()
{
Func<int> method = default(Sample3).Bar;
string name = method.Method.Name;
Assert.AreEqual("Bar", name);
}
}
Please let me know if you find a better way.
Get the latest version of this method from the MvbaCore project on github.
[...] rename accidents or any chance of missing the usage of the property when you do Find Usages. This post by Clinton Sheppard gives more detail on the [...]
V. Nice… Thanks.
[...] { /// <summary> /// From: /// http://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/ /// </summary> public static class ReflUtil [...]
Nice thoughts, thanks for sharing!
Nice tip, just what I was looking for.
Cheers, Chris.
Nice post..this is exactly what i was looking for…
thanks.
Thanks for your post, this was very helpful !
Thanks for your post, helpful in figuring out LINQ Expressions
This is very nice. Thanks!
An excellent post. Something I’ve been trying to get my head around for a bit. Thank you so much!
[...] technique is known as static reflection and is really useful in such scenarios, but … now I could not use the HasMany() methods to map a [...]
This is an excellent technique that I have used, and recently expanded upon with a complimenting extension method.
http://py-sty.blogspot.com/2011/04/getting-net-property-names-without.html
Wow! I was looking for these explications since long time!
Very bored to hardcode column name for DisplayMemeber of ComboBox, … or to hardcode column names to access column in grids.
I always hated using magic strings in reflection. Very useful, thanks!
with a minor modification the extension method can be a lot more practical without the ugliness. Change this:
public static string GetPropertyName(this Expression<Func> expression)
to this:
public static string GetPropertyName(this T obj, Expression<Func> property) where T : class
This works on Instances rather than the class itself, however I’ve found this is 99% of the time I want to get the property name. (such as firing a PropertyChanged event.
Usage becomes something like:
var propertyName = someInstance.GetPropertyName(x=>x.MyProperty);
or more commonly
var propertyName = this.GetPropertyName(x=>x.MyProperty);
Gah, that mutilated the code. Func should be Func<T, TReturn>
Great Post. The comment by Steve Py above is exactly what I was looking for, so special thanks to him. I did get a lot more from the blog itself, reading through the different ways we can get the property names.
Why dont you make your class a generic? i think its nicer:
public class PropertyName{
public static string Get(Func accessExpression)
{//yourcode}
}
public class PropertyName{
public static PropertyName For(T item){
return new PropertyName();
}
}
Then if you have an instance, you can say:
PropertyName.For(instance),Get(i=>i.Foo);
or if you dont, you do:
PropertyName.Get(i=>i.Foo);
in both case you get very nice intellisense support
[...] Other lines of research… How about an extension method: public static class Extensions This solution still isn’t particularly obvious in intent but at least we can do it all on one line without any magic strings or objects that only exist to provide access to the instance property. public static string GetPropertyName ( this Expression > expression) string name = ReflectionUtility.GetPropertyName((Sample2 s) => s.Foo); public void Should_be_able_to_get_the_name_using_an_Extension() How to get C# property names without magic strings – static reflection « Cℓinton's Blog [...]
This worked great for me too. Thanks a ton.
Thank you so much. This is a life-saver.
This can be also applicable when, if, say, you’d ever want to generate DB schema automatically based on property names of your C# objects. I mean, literally, putting (auto-formatted?) property names into SQL statements that build the tables while traversing your Class structure.
I say “auto-formatted?”, since, perhaps you use PascalCase for properties but like to stick with underscore-delimited things in Postgres.
This is a good way to get the property names for Language strings from the resource.cs file to add [LocalizedDisplayName] attributes to your MVC view’s members.
Have you seen http://stackoverflow.com/questions/7061237/static-reflection-performance ? how to make Static reflection to perform better than normal reflection ?