Workaround for lack of 'nameof' operator in C# for type-safe databinding?
Solution 1
This code basically does that:
class Program
{
static void Main()
{
var propName = Nameof<SampleClass>.Property(e => e.Name);
Console.WriteLine(propName);
}
}
public class Nameof<T>
{
public static string Property<TProp>(Expression<Func<T, TProp>> expression)
{
var body = expression.Body as MemberExpression;
if(body == null)
throw new ArgumentException("'expression' should be a member expression");
return body.Member.Name;
}
}
(Of course it is 3.5 code...)
Solution 2
While reshefm and Jon Skeet show the proper way to do this using expressions, it should be worth noting there's a cheaper way to do this for method names:
Wrap a delegate around your method, get the MethodInfo, and you're good to go. Here's an example:
private void FuncPoo()
{
}
...
// Get the name of the function
string funcName = new Action(FuncPoo).Method.Name;
Unfortunately, this works only for methods; it does not work for properties, as you cannot have delegates to property getter or setter methods. (Seems like a silly limitation, IMO.)
Solution 3
Unless someone changes their mind, the nameof
operator looks like it's coming in C# 6. Here are the design meeting notes about it:
https://roslyn.codeplex.com/discussions/552376
https://roslyn.codeplex.com/discussions/552377
Solution 4
An extension to what reshefm did, that simplified the usage of the nameof() operator, and gives the names of methods and class members and methods as well:
/// <summary>
/// Provides the <see cref="nameof"/> extension method that works as a workarounds for a nameof() operator,
/// which should be added to C# sometime in the future.
/// </summary>
public static class NameOfHelper
{
/// <summary>
/// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression.
/// </summary>
/// <typeparam name="T">The type of the <paramref name="obj"/> parameter.</typeparam>
/// <typeparam name="TProp">The type of the property (or the method's return type), which is used in the <paramref name="expression"/> parameter.</typeparam>
/// <param name="obj">An object, that has the property (or method), which its name is returned.</param>
/// <param name="expression">A Lambda expression of this pattern: x => x.Property <BR/>
/// Where the x is the <paramref name="obj"/> and the Property is the property symbol of x.<BR/>
/// (For a method, use: x => x.Method()</param>
/// <returns>A string that has the name of the given property (or method).</returns>
public static string nameof<T, TProp>(this T obj, Expression<Func<T, TProp>> expression)
{
MemberExpression memberExp = expression.Body as MemberExpression;
if (memberExp != null)
return memberExp.Member.Name;
MethodCallExpression methodExp = expression.Body as MethodCallExpression;
if (methodExp != null)
return methodExp.Method.Name;
throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression");
}
/// <summary>
/// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression.
/// </summary>
/// <typeparam name="TProp">The type of the property (or the method's return type), which is used in the <paramref name="expression"/> parameter.</typeparam>
/// <param name="expression">A Lambda expression of this pattern: () => x.Property <BR/>
/// Where Property is the property symbol of x.<BR/>
/// (For a method, use: () => x.Method()</param>
/// <returns>A string that has the name of the given property (or method).</returns>
public static string nameof<TProp>(Expression<Func<TProp>> expression)
{
MemberExpression memberExp = expression.Body as MemberExpression;
if (memberExp != null)
return memberExp.Member.Name;
MethodCallExpression methodExp = expression.Body as MethodCallExpression;
if (methodExp != null)
return methodExp.Method.Name;
throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression");
}
}
To use it:
static class Program
{
static void Main()
{
string strObj = null;
Console.WriteLine(strObj.nameof(x => x.Length)); //gets the name of an object's property.
Console.WriteLine(strObj.nameof(x => x.GetType())); //gets the name of an object's method.
Console.WriteLine(NameOfHelper.nameof(() => string.Empty)); //gets the name of a class' property.
Console.WriteLine(NameOfHelper.nameof(() => string.Copy(""))); //gets the name of a class' method.
}
}
Solution 5
The workaround is to use an expression tree, and to take that expression tree apart to find the relevant MemberInfo
. There's slightly more detail and comment in this note (although not the code to pull out the member - that's in another SO question somewhere, I believe).
Unfortunately as expression trees don't exist in .NET 2.0, there's really no equivalent.
One solution to avoid typos is to have a set of accessors which fetch the relevant PropertyInfo
for a particular property, and unit test them. That would be the only place which had the string in it. This would avoid duplication and make refactoring easier, but it's a bit draconian.
Related videos on Youtube
Paul Kapustin
Software Engineer, Functional Programming enthusiast, Researcher (Computational Linguistics)
Updated on September 09, 2020Comments
-
Paul Kapustin over 3 years
There has been a lot of sentiment to include a
nameof
operator in C#. As an example of how this operator would work,nameof(Customer.Name)
would return the string"Name"
.I have a domain object. And I have to bind it. And I need names of properties as strings then. And I want them to be type-safe.
I remember coming across a workaround in .NET 3.5 which provided the functionality of
nameof
and involved lambda expressions. However, I have not been able to locate this workaround. Can anyone provide that workaround to me?I am also interested in a way to implement the functionality of
nameof
in .NET 2.0 if that is possible.-
Mike over 8 yearsThis issue is now solved at compile time! The
nameof
operator was implemented in C# 6.0 with .NET 4.6 and VS2015 in July 2015. The following answers are still valid for C# < 6.0.
-
-
reshefm over 15 yearsI agree. Silly limitation. I don't think it should be too hard for the compiler to understand whether it is the getter or the setter and let u use delegate it.
-
Nicolas Fall about 14 yearsis this what you are looking for? imaginarydevelopment.blogspot.com/2009/10/… it references this stackoverflow.com/questions/1329138/…
-
Paul Shmakov over 11 yearsPlease note that there is a performance penalty. Expression objects are quite expensive to create. Calling a
Foo(Expression<Func<>>)
is 200 times slower than an old fashionedFoo(string propName)
. Please vote for a compile-time nameof operator. -
Arturo Martinez over 9 yearsI've been waiting this for so long. So nice to see it being implemented.
-
lolo_house over 7 yearsI created the generic method: public static string PropertyPath<T,TProp>(this T obj, Expression<Func<T, TProp>> expression) { var s = expression.Body.ToString(); var p = s.Remove(0, s.IndexOf('.') + 1); return p; }
-
DavidRR over 7 yearsAnd here is the official documentation for the
nameof
operator which did indeed become available in C# 6.0 (and Visual Studio 2015). -
DavidRR over 7 yearsFrom the documentation for the
nameof
operator (new to C# 6.0), in the section Remarks: If you need to get the fully-qualified name, you can use the typeof expression along with nameof . -
BillW over 7 yearsNote that this code must have been compiled in VS2015 in order to use Expression.Body