38

Given this class:

public class MyClass
{
    public int MyProperty {get; set;}
}

How will I be able to extract the name of MyProperty in code?

For example, I am able to get the name of the class like this

typeof(MyClass).Name

How can I do something similar for the property?

The reason for the question is that I want this particular code to be resistant against refactorizations of the names.

EDIT: With resistant I mean that I want the code at the call site to be robust in the face of changes of the propertyname. I have some stuff that is using a string representation of the property name. Sorry for the poor phrasing. I did not include call site code in order to keep the problem clean and not wander off into other discussions on the nature of the call site code.

Casper Leon Nielsen
  • 2,528
  • 1
  • 28
  • 37

7 Answers7

62

In C# 6 we can do it very simply

nameof(MyField);

you can get method\type\propery\field\class\namespace names in the same way ex

 nameof(MyClass);
 nameof(namespacename1)  // returns "namespacename1"
 nameof(TestEnum.FirstValue) // returns enum's first value

MSDN Reference

Look at this post

Nayana Priyankara
  • 1,392
  • 1
  • 18
  • 26
  • 2
    Much better solution. Make sure, if you're using Continuous Integration (like Jenkins or so), to use at least MSBuild version 14.0 in order to compile there too, otherwise it'll only compile in your dev machine. Perks of using C# 6.0 – Edgar Froes Apr 06 '17 at 14:21
  • much much better. – sertsedat Sep 04 '17 at 21:33
  • 1
    This is done at compile time. There may be reasons to want to do it dynamically at runtime as @John Leidegren showed. Eg if using an obfuscator etc, the compile time names would change. – rollsch May 16 '18 at 07:49
  • 6
    why are you upvoting a stolen answer? look the timestamp – Boppity Bop Apr 27 '19 at 13:37
  • stackoverflow shows answers by repution or timestap ?? – R.Akhlaghi May 20 '19 at 08:42
57

You do it like this, using compiler generated expression trees:

public static string GetMemberName<T, TValue>(Expression<Func<T, TValue>> memberAccess)
{
    return ((MemberExpression)memberAccess.Body).Member.Name;
}

Now call the static method from code:

class MyClass
{
    public int Field;
    public string Property { get; set; }
}

var fieldName = GetMemberName((MyClass c) => c.Field);
var propertyName = GetMemberName((MyClass c) => c.Property);
// fieldName has string value of `Field`
// propertyName has string value of `Property`

You can now also use refactoring to rename that field without breaking this code

John Leidegren
  • 59,920
  • 20
  • 131
  • 152
  • What's the chance to do something like that in Java? Or is it something C# unique (as I've seen so far)? – Vitali Pom Sep 18 '16 at 14:58
  • @VitaliPom I don't know a lot about Java. This is generated by the C# compiler. Pretty C# unique stuff, probably not something Java can do other JVM languages surly can. Would be surprised if not. – John Leidegren Sep 27 '16 at 17:13
  • How slow is this? Would it be worth caching somehow? – rollsch May 16 '18 at 07:53
  • 3
    @rolls slow and expensive, but measure first! Use the `nameof` feature of C# if possible, it can be used to reference instance members, like this `nameof(MyClass.Field)` => `"Field"` – John Leidegren May 16 '18 at 08:17
28

With C# 6.0, you can use the new nameof operator.

nameof(MyClass.MyField)  // returns "MyField"
nameof(MyClass)  //returns "MyClass"

See nameof (C# and Visual Basic Reference) for more examples.

natemcmaster
  • 25,673
  • 6
  • 78
  • 100
10

Using Reflection you can find all Members from MyClass with this.

    MemberInfo[] members = typeof(MyClass).GetMembers();

Now you can find your desired property for each Member.

    foreach ( MemberInfo memberInfo in members)
    {
        Console.WriteLine("Name: {0}", memberInfo.Name); // Name: MyField
        Console.WriteLine("Member Type: {0}", memberInfo.MemberType); // Member Type: Property
    }

If you want to find only Properties use PropertyInfo instead of MemberInfo. Or write this

    foreach ( MemberInfo memberInfo in members.Where(p => p.MemberType == MemberTypes.Property))
    {
        Console.WriteLine("Name: {0}", memberInfo.Name); // Name: MyField
        Console.WriteLine("Member Type: {0}", memberInfo.MemberType); // Member Type: Property
    }
Tatul Mkrtchyan
  • 361
  • 4
  • 8
5

You could use the following class which contains a method using an expression tree as an argument to determine a member name based on a lambda expression:

public class MemberHelper<T>
{
    public string GetName<U>(Expression<Func<T, U>> expression)
    {
        MemberExpression memberExpression = expression.Body as MemberExpression;
        if (memberExpression != null)
            return memberExpression.Member.Name;

        throw new InvalidOperationException("Member expression expected");
    }
}

Then use it like so:

MemberHelper<MyClass> memberHelper = new MemberHelper<MyClass>();
string name = memberHelper.GetName(x => x.MyField);
jdavies
  • 12,784
  • 3
  • 33
  • 33
  • Using an instance is actually a good idea, you don't have to repeat the type name all over the place but the type constraint is unnecessary. e.g. why wouldn't this work for structs? – John Leidegren Sep 29 '11 at 14:49
  • @CarstenKönig: you should? I don't think that makes sense. Users should free to remove things if they think it doesn't add value. However, the MemberHelper idea could help to get _significantly_ smoother syntax at the call site. It is not useless as an answer. – sehe Sep 29 '11 at 14:59
  • @John Leidegren - Your right, I originally wrote this class for use with classes and didn't think about its potential use with structs too. Have amended the answer to reflect your suggestion. – jdavies Sep 29 '11 at 15:00
  • @sehe - ok you got a point - think is (and this happens to me a lot) - if you get unlucky and post basically the same idea seconds after another you will get downvotes very fast ... this is why I canceled my 99% ready answer with the same content - in this case everything seems just fine so I remove my comment instead ;) – Random Dev Sep 29 '11 at 15:37
  • This is as good an answer as the other one I marked - it solves my problem too. He was one minute faster on the trigger ;) – Casper Leon Nielsen Sep 29 '11 at 16:24
3

If you only want to get name of an instance member, you can use shorter code:

    public static string GetMemberName<TValue>(Expression<Func<TValue>> memberAccess)
    {
        return ((MemberExpression)memberAccess.Body).Member.Name;
    }

And use it like the following inside the class:

    ReflectionTools.GetMemberName(() => _someInstanceVariableOrProperty)
Display Name
  • 8,022
  • 3
  • 31
  • 66
1

If you don’t want to waste your time, try the following one. I know there will be people run into the same problem.

// Soner - tested!
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(item))
{
    string name = descriptor.Name;              // Name
    object value = descriptor.GetValue(item);   // Value
    var type = descriptor.PropertyType;         // Type
    Console.WriteLine($"{name}={value}={type}");
}

Don’t forget to add using System.ComponentModel;.