views:

888

answers:

6

There's been a lot of wishes to include nameof () operator in C#, so that you could do, for instance, nameof (Customer.Name), which will return you "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 typesafe.

I remember, there was a workaround for .NET 3.5 which involved lambda expressions, so that you could get the effect of missing "nameof" operator, but I could not find it now. Anyone can remind me? And...for .NET 2.0...is there any damn way to do it? Thanks!

+2  A: 

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.

Jon Skeet
is this what you are looking for? http://imaginarydevelopment.blogspot.com/2009/10/compile-time-safe-databinding.html it references this http://stackoverflow.com/questions/1329138/how-to-make-databinding-type-safe-and-support-refactoring
Maslow
+19  A: 

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...)

reshefm
Wow, its pretty nice.
TcKs
yeah :) very funky :)
Pure.Krome
its so lovely thanks man.
Usman Masood
+2  A: 

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.)

Judah Himango
I 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.
reshefm
A: 

If you are doing data binding have a look at "How to make Databinding type safe and support refactoring"

Ian Ringrose
+1  A: 

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.
    }
}
Ad P.