273

(See below solution I created using the answer I accepted)

I'm trying to improve the maintainability of some code involving reflection. The app has a .NET Remoting interface exposing (among other things) a method called Execute for accessing parts of the app not included in its published remote interface.

Here is how the app designates properties (a static one in this example) which are meant to be accessible via Execute:

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

So a remote user could call:

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

and the app would use reflection to find SomeClass.SomeProperty and return its value as a string.

Unfortunately, if someone renames SomeProperty and forgets to change the 3rd parm of ExposeProperty(), it breaks this mechanism.

I need to the equivalent of:

SomeClass.SomeProperty.GetTheNameOfThisPropertyAsAString()

to use as the 3rd parm in ExposeProperty so refactoring tools would take care of renames.

Is there a way to do this?

Okay, here's what I ended up creating (based upon the answer I selected and the question he referenced):

// <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 with this cool capability, it's time to simplify the ExposeProperty method. Polishing doorknobs is dangerous work...

6
  • 10
    Its really appriciated that you added your solution and tied things up. Commented Oct 3, 2012 at 7:41
  • possible duplicate of Get property name and type using lambda expression Commented Apr 27, 2013 at 14:16
  • You should add your solution as an answer – it's much more concise than the answer your accepted. Commented Jan 29, 2016 at 17:46
  • 1
    @Kenny Evitt: Done : ) Commented Jan 29, 2016 at 22:51
  • @JimC Upvoted! And linked in a comment on the currently accepted answer. Thanks! Commented Jan 29, 2016 at 23:04

13 Answers 13

639

With C# 6.0, this is now a non-issue as you can do:

nameof(SomeProperty)

This expression is resolved at compile-time to "SomeProperty".

MSDN documentation of nameof.

Sign up to request clarification or add additional context in comments.

7 Comments

This is badass and very useful for ModelState.AddModelError calls.
@RaidenCore sure, if you're writing for a microcontroller you should use a low-level language like C, and if you need to squeeze every bit of performance like image and video processing, you should use C or C++. but for the other 95% of applications, a managed code framework will be fast enough. Eventually C# is also compiled to machine code, and you can even pre-compile it to native if you want.
By the way, @RaidenCore, the apps you mentioned predate C#, that's why they're written in C++. If they were written today, who knows what language was used. See e.g. Paint.NET.
This is really usefull when you want to RaiseProperty in WPF ! Use RaisePropertyChanged(nameof(property)) instead of RaisePropertyChanged("property")
nameof is cool as long as you won't apply obfuscation, if your property name is assigned to DisplayMember of any control then unfortunately this will not work because nameof is compile time and then obfuscation is applied, in the other hand expression body member name from first post will work with obfuscation because it is determined at run time
|
66

Using GetMemberInfo from here: Retrieving Property name from lambda expression you can do something like this:

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);
    }
}

4 Comments

That's totally cool. Looks like it would work on any property type, too.
I just tried it with both instance and static properties. So far so good.
Any idea where I can get the assembly or NuGet package that contains GetMemberInfo? I can't find anything with the 'common utilities' package for the Microsoft Enterprise Library, which is what MSDN seems to indicate contains that method. There's an "unofficial" package but being unofficial is uninspiring. JimC's answer, which is based on this one, is much more concise and doesn't rely on a seemingly unavailable library.
@KennyEvitt, the method he's referencing is one written by the author of the question he linked. Alternative to that methodyou can use this Type.GetMembers msdn.microsoft.com/en-us/library/…
22

Okay, here's what I ended up creating (based upon the answer I selected and the question he referenced):

// <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);

Comments

17

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;
    }

Sorry, this was missing some context. This was part of a larger class where TPropertySource is the class containing the property. You could make the function generic in TPropertySource to extract it from the class. I recommend taking a look at the full code from the MVVM Foundation.

6 Comments

With an example of how to call the function, this is certainly a +1. Oops, didn't see that there is one in the debug assertion - that's why making a developer horizontally scroll to get to the important portion of a line is evil ;)
Hmmm...I need to dissect this one to understand it.
Visual Studio 2008 flags "TPropertySource" as error ("cannot be found").
I just realized its a type name not just a symbol <T> as in C++. What does TPropertySource represent?
To make this compile you can just change the method signature to read public static string GetPropertyName<TPropertySource>(Expression<Func<TPropertySource, object>> expression) then call like so: var name = GetPropertyName<TestClass>(x => x.Foo);
|
10

The PropertyInfo class should help you achieve this, if I understand correctly.

  1. Type.GetProperties() method

    PropertyInfo[] propInfos = typeof(ReflectedType).GetProperties();
    propInfos.ToList().ForEach(p => 
        Console.WriteLine(string.Format("Property name: {0}", p.Name));
    

Is this what you need?

3 Comments

Nope, although I do use GetProperties when the app receives the request for "SomeSecret". The app looks up "SomeSecret" in a map to discover it needs to find a property called "SomeProperty" in a class called "SomeClass".
nameof(SomeProperty) actually eases this up from .net 4.0 onward. No need for such long hacks.
So many attempts out there that don't work. This was the most clear and functional answer to this question. THANK YOU!
6

You can use Reflection to obtain the actual names of the properties.

http://www.csharp-examples.net/reflection-property-names/

If you need a way to assign a "String Name" to a property, why don't you write an attribute that you can reflect over to get the string name?

[StringName("MyStringName")]
private string MyProperty
{
    get { ... }
}

2 Comments

Ya, that's how the app handles incoming requests for "SomeSecret", but it doesn't give me a tool for the ExposeProperty problem.
Interesting...then you could rename MyProperty to your hearts content as long as you don't mess with MyStringName, and if for some reason you do want to change it then you need to modify the ExposeProperty parm. At least I could add a comment next to the attribute with such a warning since you have to be looking at it to change the attribute's value (unlike renaming a property, which can be done from any reference location).
6

I modified your solution to chain over multiple properties:

public static string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
{
    MemberExpression me = propertyLambda.Body as MemberExpression;
    if (me == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
    }

    string result = string.Empty;
    do
    {
        result = me.Member.Name + "." + result;
        me = me.Expression as MemberExpression;
    } while (me != null);

    result = result.Remove(result.Length - 1); // remove the trailing "."
    return result;
}

Usage:

string name = GetPropertyName(() => someObject.SomeProperty.SomeOtherProperty);
// returns "SomeProperty.SomeOtherProperty"

Comments

6

Old question, but another answer to this question is to create a static function in a helper class that uses the CallerMemberNameAttribute.

public static string GetPropertyName([CallerMemberName] String propertyName = null) {
  return propertyName;
}

And then use it like:

public string MyProperty {
  get { Console.WriteLine("{0} was called", GetPropertyName()); return _myProperty; }
}

Comments

5

Based on the answer which is already in the question and on this article: https://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/ I am presenting my solution to this problem:

public static class PropertyNameHelper
{
    /// <summary>
    /// A static method to get the Propertyname String of a Property
    /// It eliminates the need for "Magic Strings" and assures type safety when renaming properties.
    /// See: http://stackoverflow.com/questions/2820660/get-name-of-property-as-a-string
    /// </summary>
    /// <example>
    /// // Static Property
    /// string name = PropertyNameHelper.GetPropertyName(() => SomeClass.SomeProperty);
    /// // Instance Property
    /// string name = PropertyNameHelper.GetPropertyName(() => someObject.SomeProperty);
    /// </example>
    /// <typeparam name="T"></typeparam>
    /// <param name="propertyLambda"></param>
    /// <returns></returns>
    public static 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;
    }
    /// <summary>
    /// Another way to get Instance Property names as strings.
    /// With this method you don't need to create a instance first.
    /// See the example.
    /// See: https://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/
    /// </summary>
    /// <example>
    /// string name = PropertyNameHelper((Firma f) => f.Firmenumsatz_Waehrung);
    /// </example>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TReturn"></typeparam>
    /// <param name="expression"></param>
    /// <returns></returns>
    public static string GetPropertyName<T, TReturn>(Expression<Func<T, TReturn>> expression)
    {
        MemberExpression body = (MemberExpression)expression.Body;
        return body.Member.Name;
    }
}

And a Test which also shows the usage for instance and static properties:

[TestClass]
public class PropertyNameHelperTest
{
    private class TestClass
    {
        public static string StaticString { get; set; }
        public string InstanceString { get; set; }
    }

    [TestMethod]
    public void TestGetPropertyName()
    {
        Assert.AreEqual("StaticString", PropertyNameHelper.GetPropertyName(() => TestClass.StaticString));

        Assert.AreEqual("InstanceString", PropertyNameHelper.GetPropertyName((TestClass t) => t.InstanceString));
    }
}

Comments

0

You can use the StackTrace class to get the name of the current function, (or if you put the code in a function, then step down a level and get the calling function).

See http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace(VS.71).aspx

2 Comments

I don't know where you had in mind to capture the stack trace, but I can't think of one that would contain the name of the property.
You can do this, but this can lead to unexpected results (including exceptions) due to compiler inlining optimizations. smelser.net/blog/post/2008/11/27/…
0

I've been using this answer to great effect: Get the property, as a string, from an Expression<Func<TModel,TProperty>>

I realize I already answered this question a while back. The only advantage my other answer has is that it works for static properties. I find the syntax in this answer much more useful because you don't have to create a variable of the type you want to reflect.

Comments

0

I had some difficulty using the solutions already suggested for my specific use case, but figured it out eventually. I don't think my specific case is worthy of a new question, so I am posting my solution here for reference. (This is very closely related to the question and provides a solution for anyone else with a similar case to mine).

The code I ended up with looks like this:

public class HideableControl<T>: Control where T: class
{
    private string _propertyName;
    private PropertyInfo _propertyInfo;

    public string PropertyName
    {
        get { return _propertyName; }
        set
        {
            _propertyName = value;
            _propertyInfo = typeof(T).GetProperty(value);
        }
    }

    protected override bool GetIsVisible(IRenderContext context)
    {
        if (_propertyInfo == null)
            return false;

        var model = context.Get<T>();

        if (model == null)
            return false;

        return (bool)_propertyInfo.GetValue(model, null);
    }

    protected void SetIsVisibleProperty(Expression<Func<T, bool>> propertyLambda)
    {
        var expression = propertyLambda.Body as MemberExpression;
        if (expression == null)
            throw new ArgumentException("You must pass a lambda of the form: 'vm => vm.Property'");

        PropertyName = expression.Member.Name;
    }
}

public interface ICompanyViewModel
{
    string CompanyName { get; }
    bool IsVisible { get; }
}

public class CompanyControl: HideableControl<ICompanyViewModel>
{
    public CompanyControl()
    {
        SetIsVisibleProperty(vm => vm.IsVisible);
    }
}

The important part for me is that in the CompanyControl class the compiler will only allow me to choose a boolean property of ICompanyViewModel which makes it easier for other developers to get it right.

The main difference between my solution and the accepted answer is that my class is generic and I only want to match properties from the generic type that are boolean.

Comments

0

it's how I implemented it , the reason behind is if the class that you want to get the name from it's member is not static then you need to create an instanse of that and then get the member's name. so generic here comes to help

public static string GetName<TClass>(Expression<Func<TClass, object>> exp)
{
    MemberExpression body = exp.Body as MemberExpression;

    if (body == null)
    {
         UnaryExpression ubody = (UnaryExpression)exp.Body;
         body = ubody.Operand as MemberExpression;
    }

     return body.Member.Name;
}

the usage is like this

var label = ClassExtension.GetName<SomeClass>(x => x.Label); //x is refering to 'SomeClass'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.