Coder Perfect

Get the property’s name as a string.

Problem

(See below for the solution I came up with based on the answer I accepted.)

I’m attempting to improve the maintainability of some reflection-based programmes. The app contains a.NET Remoting interface that exposes a method called Execute for accessing areas of the app that aren’t accessible through the published remote interface.

Here’s how the app designates attributes (in this case, a static one) that should be accessed via Execute:

RemoteMgr.ExposeProperty("SomeSecret", typeof(SomeClass), "SomeProperty");

As an example, a remote user could dial:

string response = remoteObject.Execute("SomeSecret");

and the app would look for SomeClass through reflection. Return the value of SomeProperty as a string.

Unfortunately, this approach is broken if SomeoneRenamesSomeProperty and forgets to alter the 3rd parm of ExposeProperty().

I’m looking for the equivalent of:

SomeClass.SomeProperty.GetTheNameOfThisPropertyAsAString()

to use as the third parameter in ExposeProperty so that renaming is handled by refactoring tools

Is there a way to make this happen?

Okay, here is what I came up with (depending on the answer I chose and the question he asked):

// <summary>
// Get the name of a static or instance property from a property access lambda.
// </summary>
// <typeparam name="T">Type of the property</typeparam>
// <param name="propertyLambda">lambda expression of the form: '() => Class.Property' or '() => object.Property'</param>
// <returns>The name of the property</returns>
public string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
{
    var me = propertyLambda.Body as MemberExpression;

    if (me == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
    }

    return me.Member.Name;
 }

Usage:

// Static Property
string name = GetPropertyName(() => SomeClass.SomeProperty);

// Instance Property
string name = GetPropertyName(() => someObject.SomeProperty);

Now that you have this wonderful feature, you may simplify the ExposeProperty method. It’s perilous work polishing doorknobs…

Asked by Jim C

Solution #1

This is no longer an issue in C# 6.0, as you can now do:

nameof(SomeProperty)

This expression is resolved to “SomeProperty” at compile time.

nameof documentation in MSDN.

Answered by James Ko

Solution #2

You can do something like this with GetMemberInfo from here: Retrieving Property name from lambda expression:

RemoteMgr.ExposeProperty(() => SomeClass.SomeProperty)

public class SomeClass
{
    public static string SomeProperty
    {
        get { return "Foo"; }
    }
}

public class RemoteMgr
{
    public static void ExposeProperty<T>(Expression<Func<T>> property)
    {
        var expression = GetMemberInfo(property);
        string path = string.Concat(expression.Member.DeclaringType.FullName,
            ".", expression.Member.Name);
        // Do ExposeProperty work here...
    }
}

public class Program
{
    public static void Main()
    {
        RemoteMgr.ExposeProperty("SomeSecret", () => SomeClass.SomeProperty);
    }
}

Answered by Daniel Renshaw

Solution #3

Okay, here is what I came up with (depending on the answer I chose and the question he asked):

// <summary>
// Get the name of a static or instance property from a property access lambda.
// </summary>
// <typeparam name="T">Type of the property</typeparam>
// <param name="propertyLambda">lambda expression of the form: '() => Class.Property' or '() => object.Property'</param>
// <returns>The name of the property</returns>

public string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
{
    var me = propertyLambda.Body as MemberExpression;

    if (me == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
    }

    return me.Member.Name;
 }

Usage:

// Static Property
string name = GetPropertyName(() => SomeClass.SomeProperty);

// Instance Property
string name = GetPropertyName(() => someObject.SomeProperty);

Answered by Jim C

Solution #4

There’s a well-known hack to extract it from lambda expression (this is from the PropertyObserver class, by Josh Smith, in his MVVM foundation):

    private static string GetPropertyName<TPropertySource>
        (Expression<Func<TPropertySource, object>> expression)
    {
        var lambda = expression as LambdaExpression;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambda.Body as MemberExpression;
        }

        Debug.Assert(memberExpression != null, 
           "Please provide a lambda expression like 'n => n.PropertyName'");

        if (memberExpression != null)
        {
            var propertyInfo = memberExpression.Member as PropertyInfo;

            return propertyInfo.Name;
        }

        return null;
    }

Please accept my apologies for the lack of context. TPropertySource is the class that has the property, and it was part of a larger class. To extract the function from the class, you might make it generic in TPropertySource. I recommend looking at the MVVM Foundation’s complete code.

Answered by Dan Bryant

Solution #5

If my understanding is correct, the PropertyInfo class should assist you in accomplishing this.

Is this what you’re looking for?

Answered by Will Marcouiller

Post is based on https://stackoverflow.com/questions/2820660/get-name-of-property-as-a-string