For several years I’ve had a little “utility” function that I’ve used in several projects that I use to convert property names into strings. One use case is for instance when mapping code to some data source or third party API that where the names are used as keys. The method uses “static reflection”, or rather it parses the expression tree from a lambda expression, to figure out the name of a property that the lambda expression returns the value of.
So far I haven’t really needed to do the same for methods or fields but today I decided I would try to make it a bit more generic anyway. In other words, I wanted to be able to do stuff like this:
//Should return "Length", value type property
StaticReflection.GetMemberName<string>(x => x.Length);
//Should return "Data", reference type property
StaticReflection.GetMemberName<Exception>(x => x.Data);
//Should return "Clone", method returning reference type
StaticReflection.GetMemberName<string>(x => x.Clone());
//Should return "GetHashCode", method returning value type
StaticReflection.GetMemberName<string>(x => x.GetHashCode());
//Should return "Reverse", void method
StaticReflection.GetMemberName<List<string>>(x => x.Reverse());
//Should return "LastIndexOf", method with parameter
StaticReflection.GetMemberName<string>(x => x.LastIndexOf(','));
Or, by having an overload that is an extension method achieve the same effect but utilizing type inference so we don’t have to explicitly specify the type if we have an instance of it, for instance like this:
//Should return Length, no type parameter required "someString".GetMemberName(x => x.Length);
In order to fulfill the above requirements we need two methods, one accepting a Expression<Func<T, object>> and one, used for methods without return types, an Expression<Action<T>> as parameters. We also need the corresponding extension methods. Once we have those we need to look at the Body property of the expressions and figure out what types of expressions they are. In other words, if we’re dealing with a field, property or method as well as if the return type is a value type or reference type as the way to get the name from the expression tree differs depending on that.
My solution was to create a static class with a couple of private method that did the bulk of the work.
private static string GetMemberName(Expression expression)
{
if (expression == null)
{
throw new ArgumentException(
"The expression cannot be null.");
}
if (expression is MemberExpression)
{
// Reference type property or field
var memberExpression = (MemberExpression) expression;
return memberExpression.Member.Name;
}
if (expression is MethodCallExpression)
{
// Reference type method
var methodCallExpression =
(MethodCallExpression) expression;
return methodCallExpression.Method.Name;
}
if (expression is UnaryExpression)
{
// Property, field of method returning value type
var unaryExpression = (UnaryExpression) expression;
return GetMemberName(unaryExpression);
}
throw new ArgumentException("Invalid expression");
}
private static string GetMemberName(
UnaryExpression unaryExpression)
{
if (unaryExpression.Operand is MethodCallExpression)
{
var methodExpression =
(MethodCallExpression) unaryExpression.Operand;
return methodExpression.Method.Name;
}
return ((MemberExpression) unaryExpression.Operand)
.Member.Name;
}
The if statements could be replaced with an “action map” but this form allowed me to better illustrate what the methods, especially the first one, do. Anyhow, with the private methods in place the public methods are pretty straight forward. First the static helper methods:
public static string GetMemberName<T>(Expression<Func<T, object>> expression)
{
if (expression == null)
{
throw new ArgumentException(
"The expression cannot be null.");
}
return GetMemberName(expression.Body);
}
public static string GetMemberName<T>(
Expression<Action<T>> expression)
{
if (expression == null)
{
throw new ArgumentException(
"The expression cannot be null.");
}
return GetMemberName(expression.Body);
}
And the corresponding extension methods:
public static string GetMemberName<T>(
this T instance, Expression<Func<T, object>> expression)
{
return GetMemberName(expression);
}
public static string GetMemberName<T>(
this T instance, Expression<Action<T>> expression)
{
return GetMemberName(expression);
}
Note how we’re not actually using the instance the extension methods are called on. They are only there to allow us to invoke the methods on instances of a type directly instead of specifying the type as the compiler can then infer the type parameter (T). In other words, we could in theory do something like this:
((string) null).GetMemberName(x => x.Length);
That seems a bit pointless though as we’re probably better off using the regular methods in to achieve the same result.
The full class looks like this:
public static class StaticReflection
{
public static string GetMemberName<T>(
this T instance,
Expression<Func<T, object>> expression)
{
return GetMemberName(expression);
}
public static string GetMemberName<T>(
Expression<Func<T, object>> expression)
{
if (expression == null)
{
throw new ArgumentException(
"The expression cannot be null.");
}
return GetMemberName(expression.Body);
}
public static string GetMemberName<T>(
this T instance,
Expression<Action<T>> expression)
{
return GetMemberName(expression);
}
public static string GetMemberName<T>(
Expression<Action<T>> expression)
{
if (expression == null)
{
throw new ArgumentException(
"The expression cannot be null.");
}
return GetMemberName(expression.Body);
}
private static string GetMemberName(
Expression expression)
{
if (expression == null)
{
throw new ArgumentException(
"The expression cannot be null.");
}
if (expression is MemberExpression)
{
// Reference type property or field
var memberExpression =
(MemberExpression) expression;
return memberExpression.Member.Name;
}
if (expression is MethodCallExpression)
{
// Reference type method
var methodCallExpression =
(MethodCallExpression) expression;
return methodCallExpression.Method.Name;
}
if (expression is UnaryExpression)
{
// Property, field of method returning value type
var unaryExpression = (UnaryExpression) expression;
return GetMemberName(unaryExpression);
}
throw new ArgumentException("Invalid expression");
}
private static string GetMemberName(
UnaryExpression unaryExpression)
{
if (unaryExpression.Operand is MethodCallExpression)
{
var methodExpression =
(MethodCallExpression) unaryExpression.Operand;
return methodExpression.Method.Name;
}
return ((MemberExpression) unaryExpression.Operand)
.Member.Name;
}
}
For the really interested person, it passes a number of tests, or executable specifications verified and generated using MSpec, producing the following specification:
StaticReflection GetMemberName, given a Func returning a value type property
» should return the name of the property
StaticReflection GetMemberName, given a Func returning a reference type property
» should return the name of the property
StaticReflection GetMemberName, given a Func invoking a reference type method
» should return the name of the method
StaticReflection GetMemberName, given a Func invoking a value type method
» should return the name of the method
StaticReflection GetMemberName, given a Func invoking a void method
» should return the name of the method
StaticReflection GetMemberName, given a Func invoking a method with a parameter
» should return the name of the method
StaticReflection GetMemberName, called with null cast to Func
» should throw an exception
» should throw an ArgumentException
StaticReflection GetMemberName, called with null cast to Action
» should throw an exception
» should throw an ArgumentException
PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.
This blog is built with EPiServer Community, EPiServer CMS, ASP.NET MVC and a bunch of other great products. The source code is available for download at the projects page, where you also can read more about this site and my other projects.
read more
Comments
Michael 7 months ago
Excellent - thank you for taking the time to share this.
Roger Norling 6 months ago
Nice, I were looking for something like this. I took the opportunity to improve on this though. You can get rid of the object type in the delegates by declaring them e.g. Func<T, TResult> and change the method generic parameters to GetMemberName<T, TResult> . This means the generics are implicit and the lambda parameter type is made explicit instead. With a more fluent naming it might look like this:
I've also added support for static methods, properties and fields. I skipped the extension methods since I don't find it useful to create new instances just to extract a name. It is still useful to use 'this' inside a method to get it's own name in a refactoring safe way though. I don't have null checks, but I see this as a utility so the arguments should be trusted.
Here is my code (http://pastebin.com/j0neZ478), with NUnit tests (http://pastebin.com/tu4neNQr).
Shankar 5 months ago
I am struggling to find the property name from string , lets say i have sting "AccountName" , i am passing that string to some method, can i get property from that string , i know there is property called AccountName for some model, by just passing string can i get the property.
Michael 5 months ago
@Shankar: I don't think that's possible: the only type that you can reflect on in your scenario is [string]; where that string came from is no longer available at that point.
Roger Norling 5 months ago
Shankar: A string is just a string, so if you only have access to the name of the property then you can't do much more. If you have access to an instance on the other hand, you can do this http://pastebin.com/XSYHvssA .
Note though that all exception checking is skipped for the sake of the example. The less you know about your objects in your code the more you need to check for errors (This includes changes you do due to developing your code).