I was recently asked how a particular GetPropertyName function my team was using worked. This is what I said:
Usage Example
C#
1
2
3
4
5
6
7
8
9
10
static void Main(string[] args)
{
var demoClass = new Demo();
Console.WriteLine("demoClass.{0}: {1}",
Utilities.GetPropertyName(() => demoClass.TestProperty),
demoClass.TestProperty);
Console.WriteLine("demoClass.{0}: {1}",
Utilities.GetPropertyName(() => demoClass.TestNumber),
demoClass.TestNumber);
}
VB.NET
1
2
3
4
5
6
7
8
9
Sub Main()
Dim demoClass As New Demo()
Console.WriteLine("demoClass.{0}: {1}",
GetPropertyName(Function() demoClass.TestProperty),
demoClass.TestProperty)
Console.WriteLine("demoClass.{0}: {1}",
GetPropertyName(Function() demoClass.TestNumber),
demoClass.TestNumber)
End Sub
Usage Explanation
The first line prints of the method prints the name of the demoClass’s TestProperty property and its value. The second line prints the name of the demoClass’s TestNumber property and its value.
GetPropertyName Function Overview
The GetPropertyName function returns a string.
The GetPropertyName function takes a single input argument which must be a lambda expression. The lambda expression must be a function. The function must contain a single statement that returns the value of one of the object’s properties.
The GetPropertyName function uses built-in .NET framework functionality to get the name of the property that was accessed by the lambda expression and returns that property name as a string.
More information about lambda expressions:
- Lambda Expressions (Visual Basic)
[http://msdn.microsoft.com/en-us/library/bb531253.aspx]
https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/lambda-expressions - How to: Create a Lambda Expression (Visual Basic)
[http://msdn.microsoft.com/en-us/library/bb531298.aspx]
https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/how-to-create-a-lambda-expression - Lambda Expressions (C# Programming Guide)
[http://msdn.microsoft.com/en-us/library/bb397687.aspx]
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions - How to: Use Lambda Expressions Outside LINQ (C# Programming Guide)
[http://msdn.microsoft.com/en-us/library/bb383984.aspx]
https://web.archive.org/web/20160611152450/http://msdn.microsoft.com/en-us/library/bb383984.aspx
GetPropertyName Code
C#
1
2
3
4
public static string GetPropertyName<T>(Expression<Func<T>> expression)
{
return ((MemberExpression)expression.Body).Member.Name;
}
- The
<T>
inGetPropertyName<T>
is used to genericize the class that is used in the lambda expression. - The
Expression<Func<T>>
in(Expression<Func<T>> expression)
indicates the input argument to the GetPropertyName function must be a lambda expression that is a function that uses an object of type “T”.Expression
is a special .NET Framework datatype that causes the compiler to create and populate a data structure that contains details about the code inside a lambda expression. More information about this data type can be found athttp://msdn.microsoft.com/en-us/library/Bb335710.aspxhttps://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions.expression-1. expression.Body
gets the body of the lambda expression.((MemberExpression)expression.Body)
casts the body of the lambda expression to aMemberExpression
. AMemberExpression
is a datatype that represents a class’ property being accessed. If the lambda expression passed into the GetPropertyName function is not a single line of code that accesses a class property, anInvalidCastException
will be thrown at runtime.- The
Member
property of theMemberExpression
datatype represents the property being accessed. It is of typeMemberInfo
. - The
Name
property of theMemberInfo
type returns the name of the property as a string.
VB.NET
1
2
3
Public Function GetPropertyName(Of T)(expression As Expression(Of Func(Of T))) As String
Return DirectCast(expression.Body, MemberExpression).Member.Name
End Function
- The
(Of T)
inGetPropertyName(Of T)
is used to genericize the class that is used in the lambda expression. - The
Expression(Of Func(Of T))
in(expression As Expression(Of Func(Of T)))
indicates the input argument to the GetPropertyName function must be a lambda expression that is a function that uses an object of type “T”.Expression
is a special .NET Framework datatype that causes the compiler to create and populate a data structure that contains details about the code inside a lambda expression. More information about this data type can be found athttp://msdn.microsoft.com/en-us/library/Bb335710.aspxhttps://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions.expression-1. expression.Body
gets the body of the lambda expression.DirectCast(expression.Body, MemberExpression)
casts the body of the lambda expression to aMemberExpression
. AMemberExpression
is a datatype that represents a class’ property being accessed. If the lambda expression passed into the GetPropertyName function is not a single line of code that accesses a class property, anInvalidCastException
will be thrown at runtime.- The
Member
property of theMemberExpression
datatype represents the property being accessed. It is of typeMemberInfo
. - The
Name
property of theMemberInfo
type returns the name of the property as a string.
Why are we using GetPropertyName?
So why do we use GetPropertyName instead of just passing in a string constant (see alternate code below)?
C#
1
2
3
4
5
6
7
8
9
10
static void AlternateVersion()
{
var demoClass = new Demo();
Console.WriteLine("demoClass.{0}: {1}",
"TestProperty",
demoClass.TestProperty);
Console.WriteLine("demoClass.{0}: {1}",
"TestNumber",
demoClass.TestNumber);
}
VB.NET
1
2
3
4
5
6
7
8
9
Sub AlternateVersion()
Dim demoClass As New Demo()
Console.WriteLine("demoClass.{0}: {1}",
"TestProperty",
demoClass.TestProperty)
Console.WriteLine("demoClass.{0}: {1}",
"TestNumber",
demoClass.TestNumber)
End Sub
If the name of a demoClass’s property changes, the developer needs to remember to update the code to use the new name. The string is not tied to the class at all. One alternative would be to add readonly properties to the class that returned the name of the properties (e.g. Demo.TestPropertyName or something like that), but the developer would still need to remember to update that property’s name if its associated property’s name changed.
By using the GetPropertyName function, if a property is renamed, Resharper can automatically rename our GetPropertyName lambda expressions. If we are not using Resharper and we rename a property, we will get a compiler error if we forget to update the property's name wherever it is used.