265

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

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Jim C
  • 4,517
  • 7
  • 29
  • 33
  • 10
    Its really appriciated that you added your solution and tied things up. – Simply G. Oct 03 '12 at 07:41
  • possible duplicate of [Get property name and type using lambda expression](http://stackoverflow.com/questions/273941/get-property-name-and-type-using-lambda-expression) – nawfal Apr 27 '13 at 14:16
  • You should add your solution as an answer – it's much more concise than the answer your accepted. – Kenny Evitt Jan 29 '16 at 17:46
  • 1
    @Kenny Evitt: Done : ) – Jim C Jan 29 '16 at 22:51
  • @JimC Upvoted! And linked in [a comment on the currently accepted answer](http://stackoverflow.com/questions/2820660/get-name-of-property-as-a-string?noredirect=1#comment57912937_2820759). Thanks! – Kenny Evitt Jan 29 '16 at 23:04
  • Keep scrolling for the [real answer](https://stackoverflow.com/a/31103473/1713149). I almost missed it! – Joel Christophel Oct 06 '20 at 17:30

13 Answers13

621

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.

James Ko
  • 32,215
  • 30
  • 128
  • 239
  • 23
    This is badass and very useful for ModelState.AddModelError calls. – Michael Silver Dec 12 '15 at 19:09
  • @TsahiAsher native languages are slow like hell, Microsoft acknowledged that, they are working on a native version of C# for their UWP, apple knew that long ago, killed the garbage collected version of objective C for the preference of the ARC. iphones runs faster with much less memory and CPU speed because they dont use Java. Microcontroller programmers continue to use C and C++. All major applications are written in C++, Photoshop, 3dMax, Autocad, MS Office, they suffer from the complexity of the native languages for their software to be actually useful. image processing, video encoding.... – Raiden Core Jan 17 '17 at 22:54
  • @TsahiAsher website servers are just text processors, they can live with managed code where a lot of the hardware resources are wasted till they get so popular they will search for alternatives like facebook did. – Raiden Core Jan 17 '17 at 22:58
  • 6
    @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. – Tsahi Asher Jan 18 '17 at 07:54
  • 5
    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. – Tsahi Asher Jan 18 '17 at 08:37
  • 4
    This is really usefull when you want to `RaiseProperty` in WPF ! Use RaisePropertyChanged(nameof(property)) instead of RaisePropertyChanged("property") – Pierre Mar 02 '17 at 09:17
  • 3
    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 – Zenon Feb 16 '20 at 01:46
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);
    }
}
Rob
  • 26,989
  • 16
  • 82
  • 98
Daniel Renshaw
  • 33,729
  • 8
  • 75
  • 94
  • That's totally cool. Looks like it would work on any property type, too. – Jim C May 12 '10 at 16:37
  • I just tried it with both instance and static properties. So far so good. – Jim C May 12 '10 at 16:50
  • 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](http://stackoverflow.com/a/35095504/173497), which is based on this one, is much more concise and doesn't rely on a seemingly unavailable library. – Kenny Evitt Jan 29 '16 at 23:03
  • 1
    @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 https://msdn.microsoft.com/en-us/library/system.type.getmembers%28v=vs.110%29.aspx – Bon Mar 30 '16 at 21:25
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);
Jim C
  • 4,517
  • 7
  • 29
  • 33
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.

Rikin Patel
  • 8,848
  • 7
  • 70
  • 78
Dan Bryant
  • 27,329
  • 4
  • 56
  • 102
  • 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 ;) – OregonGhost May 12 '10 at 16:18
  • Hmmm...I need to dissect this one to understand it. – Jim C May 12 '10 at 16:26
  • Visual Studio 2008 flags "TPropertySource" as error ("cannot be found"). – Jim C May 12 '10 at 16:53
  • I just realized its a type name not just a symbol as in C++. What does TPropertySource represent? – Jim C May 12 '10 at 16:58
  • 2
    To make this compile you can just change the method signature to read `public static string GetPropertyName(Expression> expression)` then call like so: `var name = GetPropertyName(x => x.Foo);` – dav_i Feb 03 '14 at 10:48
  • It would be interesting to edit the answer to add this bit of information: [Why are some object properties UnaryExpression and others MemberExpression?](https://stackoverflow.com/a/3573250/8133067) – Pedro Gaspar Nov 02 '18 at 14:27
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?

Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • 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". – Jim C May 12 '10 at 16:38
  • nameof(SomeProperty) actually eases this up from .net 4.0 onward. No need for such long hacks. – Mantra Jan 21 '20 at 11:44
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"
hypehuman
  • 1,290
  • 2
  • 18
  • 37
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 { ... }
}
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • 1
    Ya, that's how the app handles incoming requests for "SomeSecret", but it doesn't give me a tool for the ExposeProperty problem. – Jim C May 12 '10 at 16:19
  • 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). – Jim C May 12 '10 at 16:34
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; }
}
Jim Pedid
  • 2,730
  • 3
  • 23
  • 27
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));
    }
}
Thomas
  • 2,127
  • 1
  • 32
  • 45
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

Sprotty
  • 5,676
  • 3
  • 33
  • 52
  • 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. – Jim C May 12 '10 at 16:25
  • You can do this, but this can lead to unexpected results (including exceptions) due to compiler inlining optimizations. http://www.smelser.net/blog/post/2008/11/27/Be-carefull-with-that-Stack-Trace.aspx – JoeGeeky May 12 '10 at 18:34
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.

Community
  • 1
  • 1
hypehuman
  • 1,290
  • 2
  • 18
  • 37
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.

halfer
  • 19,824
  • 17
  • 99
  • 186
bikeman868
  • 2,236
  • 23
  • 30
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'
Mohammad Hossein Amri
  • 1,842
  • 2
  • 23
  • 43