How to get current property name via reflection?

31,615

Solution 1

Since properties are really just methods you can do this and clean up the get_ returned:

class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            var x = p.Something;
            Console.ReadLine();
        }

        public string Something
        {
            get
            {
                return MethodBase.GetCurrentMethod().Name;
            }
        }
    }

If you profile the performance you should find MethodBase.GetCurrentMethod() is miles faster than StackFrame. In .NET 1.1 you will also have issues with StackFrame in release mode (from memory I think I found it was 3x faster).

That said I'm sure the performance issue won't cause too much of a problem- though an interesting discussion on StackFrame slowness can be found here.

I guess another option if you were concerned about performance would be to create a Visual Studio Intellisense Code Snippet that creates the property for you and also creates a string that corresponds to the property name.

Solution 2

Slightly confusing example you presented, unless I just don't get it. From C# 6.0 you can use the nameof operator.

public CarType MyProperty
{
    get { return (CarType)this[nameof(MyProperty)]};
    set { this[nameof(MyProperty)] = value]};
}

If you have a method that handles your getter/setter anyway, you can use the C# 4.5 CallerMemberName attribute, in this case you don't even need to repeat the name.

public CarType MyProperty
{
    get { return Get<CarType>(); }
    set { Set(value); }
}

public T Get<T>([CallerMemberName]string name = null)
{
    return (T)this[name];
}

public void Set<T>(T value, [CallerMemberName]string name = null)
{
    this[name] = value;
}

Solution 3

I'd like to know more about the context in which you need it since it seems to me that you should already know what property you are working with in the property accessor. If you must, though, you could probably use MethodBase.GetCurrentMethod().Name and remove anything after get_/set_.

Update:

Based on your changes, I would say that you should use inheritance rather than reflection. I don't know what data is in your dictionary, but it seems to me that you really want to have different Car classes, say Sedan, Roadster, Buggy, StationWagon, not keep the type in a local variable. Then you would have implementations of methods that do the proper thing for that type of Car. Instead of finding out what kind of car you have, then doing something, you then simply call the appropriate method and the Car object does the right thing based on what type it is.

 public interface ICar
 {
      void Drive( decimal velocity, Orientation orientation );
      void Shift( int gear );
      ...
 }

 public abstract class Car : ICar
 {
      public virtual void Drive( decimal velocity, Orientation orientation )
      {
          ...some default implementation...
      }

      public abstract void Shift( int gear );

      ...
 }

 public class AutomaticTransmission : Car
 {
       public override void Shift( int gear )
       {
          ...some specific implementation...
       }
 }

 public class ManualTransmission : Car
 {
       public override void Shift( int gear )
       {
          ...some specific implementation...
       }
 }

Solution 4

Use MethodBase.GetCurrentMethod() instead!

Reflection is used to do work with types that can't be done at compile time. Getting the name of the property accessor you're in can be decided at compile time so you probably shouldn't use reflection for it.

You get use the accessor method's name from the call stack using System.Diagnostics.StackTrace though.

string GetPropertyName()
{
    StackTrace callStackTrace = new StackTrace();
    StackFrame propertyFrame = callStackTrace.GetFrame(1); // 1: below GetPropertyName frame
    string properyAccessorName = propertyFrame.GetMethod().Name;

    return properyAccessorName.Replace("get_","").Replace("set_","");
}

Solution 5

FWIW I implemented a system like this:

    [CrmAttribute("firstname")]
    public string FirstName
    {
       get { return GetPropValue<string>(MethodBase.GetCurrentMethod().Name); }
       set { SetPropValue(MethodBase.GetCurrentMethod().Name, value); }
    }

    // this is in a base class, skipped that bit for clairty
    public T GetPropValue<T>(string propName)
    {
        propName = propName.Replace("get_", "").Replace("set_", "");
        string attributeName = GetCrmAttributeName(propName);
        return GetAttributeValue<T>(attributeName);            
    }

    public void SetPropValue(string propName, object value)
    {
        propName = propName.Replace("get_", "").Replace("set_", "");
        string attributeName = GetCrmAttributeName(propName);
        SetAttributeValue(attributeName, value);
    }

    private static Dictionary<string, string> PropToAttributeMap = new Dictionary<string, string>();
    private string GetCrmAttributeName(string propertyName)
    {
         // keyName for our propertyName to (static) CrmAttributeName cache
         string keyName = this.GetType().Name + propertyName;
         // have we already done this mapping?
         if (!PropToAttributeMap.ContainsKey(keyName))
         {
             Type t = this.GetType();
             PropertyInfo info = t.GetProperty(propertyName);
             if (info == null)
             {
                 throw new Exception("Cannot find a propety called " + propertyName);
             }

             object[] attrs = info.GetCustomAttributes(false);
             foreach (object o in attrs)
             {
                 CrmAttributeAttribute attr = o as CrmAttributeAttribute ;
                 if (attr != null)
                 {
                     // found it. Save the mapping for next time.
                     PropToAttributeMap[keyName] = attr.AttributeName;
                     return attr.AttributeName;
                 }
              }
              throw new Exception("Missing MemberOf attribute for " + info.Name + "." + propertyName + ". Could not auto-access value");
           }

           // return the existing mapping
           string result = PropToAttributeMap[keyName];
           return result;
        }

There's also a custom attribute class called CrmAttributeAttribute.

I'd strongly recommend against using GetStackFrame() as part of your solution, my original version of the solution was originally the much neater:

return GetPropValue<string>();

But it was 600x slower than the version above.

Share:
31,615
Tom Smykowski
Author by

Tom Smykowski

Updated on January 12, 2020

Comments

  • Tom Smykowski
    Tom Smykowski over 4 years

    I would like to get property name when I'm in it via reflection mechanism. Is it possible?

    Update: I have code like this:

        public CarType Car
        {
            get { return (Wheel) this["Wheel"];}
            set { this["Wheel"] = value; }
        }
    

    And because I need more properties like this I would like to do something like this:

        public CarType Car
        {
            get { return (Wheel) this[GetThisPropertyName()];}
            set { this[GetThisPropertyName()] = value; }
        }
    
  • Tom Smykowski
    Tom Smykowski almost 15 years
    I've added some more explanation of my context.
  • Noam Gal
    Noam Gal almost 15 years
    Your updates just show why you shouldn't try using reflection for it. Using the suggested reflection way, you'd probably end up finding out you are inside "GetThisPropertyName", and decide you re the "ThisPropertyName" property. You will have to tweak the example to go one stack call "down", in order to get the actual property call. While it is possible, it looks like an overkill. Your code will be sprinkled with copy/pastes of this[GetThisPropertyName()] calls, and it won't be any more readable (IMHO). I'd stick to using the normal string dict accessor, personally.
  • Bobby Adams
    Bobby Adams almost 15 years
    Interesting -- I wasn't aware of GetCurrentMethod()
  • Kharlos Dominguez
    Kharlos Dominguez about 12 years
    I have been doing things like this and it caught me back. Beware it may cause problems if the property is inlined: putting [MethodImpl(MethodImplOptions.NoInlining)] before the getter/setter can help though, but it is inconvenient...
  • Serj Sagan
    Serj Sagan over 9 years
    Is thee something similar to this for Properties?
  • Niklas
    Niklas over 6 years
    i keep forgetting about the magic of nameof every single time. this is much easier to just call the nameof(property) other than all the other solutions i saw. confirming that just doing the nameof(item.PropertyName) worked like a charm for me. although it might differ for others depending on their situation.
  • Mike Fuchs
    Mike Fuchs over 6 years
    @Niklas nameof is one of the greatest syntax improvements ever introduced to C#. Makes using literal strings in code nearly obsolete, thus not only improving convenience but also code safety. I use it all the time.