Как получить текущее имя свойства через отражение? - PullRequest
38 голосов
/ 30 июля 2009

Я хотел бы получить имя свойства, когда я в нем через механизм отражения. Возможно ли это?

Обновление: У меня есть такой код:

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

И так как мне нужно больше таких свойств, я хотел бы сделать что-то вроде этого:

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

Ответы [ 8 ]

51 голосов
/ 30 июля 2009

Поскольку свойства на самом деле являются просто методами, вы можете сделать это и очистить возвращаемое значение get_:

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

Если вы профилируете производительность, вы обнаружите, что MethodBase.GetCurrentMethod () в милях быстрее, чем StackFrame. В .NET 1.1 у вас также будут проблемы со StackFrame в режиме выпуска (из памяти, я думаю, я нашел это в 3 раза быстрее).

Тем не менее, я уверен, что проблема с производительностью не вызовет особых проблем, хотя интересное обсуждение медленности StackFrame можно найти здесь .

Я думаю, что другой вариант, если вас беспокоит производительность, - это создание фрагмента кода Visual Studio Intellisense, который создает свойство для вас, а также создает строку, соответствующую имени свойства.

7 голосов
/ 30 июля 2009

Я хотел бы узнать больше о контексте, в котором он вам нужен, поскольку мне кажется, что вы уже должны знать, с каким свойством вы работаете в аксессоре свойств. Однако, если вы должны это сделать, вы можете использовать MethodBase.GetCurrentMethod () .Name и удалить что-либо после get_/set_.

.

Обновление

Исходя из ваших изменений, я бы сказал, что вы должны использовать наследование, а не рефлексию. Я не знаю, какие данные есть в вашем словаре, но мне кажется, что вы действительно хотите иметь разные классы Car, скажем, Sedan, Roadster, Buggy, StationWagon, а не хранить тип в локальной переменной. Тогда у вас будут реализации методов, которые делают правильные вещи для этого типа автомобилей. Вместо того, чтобы выяснить, какая у вас машина, а затем что-то делать, вы просто вызываете соответствующий метод, и объект Car делает правильные вещи, основываясь на том, какой это тип.

 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...
       }
 }
5 голосов
/ 07 февраля 2017

Слегка сбивающий с толку пример, который вы привели, если только я его не понимаю. Из C # 6.0 вы можете использовать оператор nameof.

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

Если у вас есть метод, который все равно обрабатывает ваш метод получения / установки, вы можете использовать атрибут C # 4.5 CallerMemberName, в этом случае вам даже не нужно повторять имя.

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;
}  
5 голосов
/ 30 июля 2009

Используйте взамен MethodBase.GetCurrentMethod ()!

Отражение используется для работы с типами, которые не могут быть выполнены во время компиляции. Получить имя аксессора свойства, в котором вы находитесь, можно во время компиляции, поэтому вам, вероятно, не следует использовать для него отражение.

Вы можете использовать имя метода доступа из стека вызовов, используя System.Diagnostics.StackTrace.

    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_","");
    }
3 голосов
/ 17 мая 2011

FWIW Я реализовал такую ​​систему:

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

Существует также собственный класс атрибутов с именем CrmAttributeAttribute.

Я бы настоятельно рекомендовал против , используя GetStackFrame () в качестве части вашего решения, моя оригинальная версия решения была гораздо более аккуратной:

return GetPropValue<string>();

Но это было в 600 раз медленнее, чем версия выше.

0 голосов
/ 08 января 2019

Путь № 1

var a = nameof(SampleMethod);    //a == SampleMethod
var b = nameof(SampleVariable);  //b == SampleVariable
var c = nameof(SampleProperty);  //c == SampleProperty

Путь № 2

MethodBase.GetCurrentMethod().Name; // Name of method in which you call the code
MethodBase.GetCurrentMethod().Name.Replace("set_", "").Replace("get_", ""); // current Property

Путь № 3

от StackTrace:

public static class Props
{
    public static string CurrPropName => 
         (new StackTrace()).GetFrame(1).GetMethod().Name.Replace("set_", "").Replace("get_", "");

    public static string CurrMethodName => 
        (new StackTrace()).GetFrame(1).GetMethod().Name;
}

вам просто нужно позвонить Props.CurrPropName или Props.CurrMethodName


Путь № 4

Решение для .NET 4.5 +:

public static class Props
{
    public static string GetCallerName([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
    {
         return propertyName;
    }
}

usgae: Props.GetCallerName();

0 голосов
/ 30 июля 2009

Попробуйте использовать System.Diagnostics.StackTrace для отражения в стеке вызовов. Свойство должно быть где-то в стеке вызовов (возможно, наверху, если вы вызываете его непосредственно из кода свойства).

0 голосов
/ 30 июля 2009

Да, это так!

string test = "test string";
Type type = test.GetType();

PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < propInfos.Length; i++) 
{
    PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i);
    string propName = pi.Name;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...