【问题标题】:How to get current property name via reflection?如何通过反射获取当前属性名称?
【发布时间】:2010-11-15 09:58:45
【问题描述】:

我想通过反射机制获取属性名称。有可能吗?

更新: 我有这样的代码:

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

因为我需要更多这样的属性,所以我想做这样的事情:

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

【问题讨论】:

  • +1 我在实现 System.Configuration.ApplicationSettingsBase 时也想知道这个

标签: c# reflection properties


【解决方案1】:

方式#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.CurrPropNameProps.CurrMethodName


方式#4

.NET 4.5+ 的解决方案:

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

usgae:Props.GetCallerName();

【讨论】:

    【解决方案2】:

    您提供的示例有点令人困惑,除非我只是不明白。 从 C# 6.0 开始,您可以使用 nameof 运算符。

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

    如果您有一个方法可以处理您的 getter/setter,您可以使用 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;
    }  
    

    【讨论】:

    • 我每次都忘记nameof 的魔力。这比我看到的所有其他解决方案更容易调用nameof(property)。确认只是做nameof(item.PropertyName) 对我来说就像一种魅力。尽管其他人的情况可能会有所不同。
    • @Niklas nameof 是 C# 有史以来最伟大的语法改进之一。使在代码中使用文字字符串几乎过时,从而不仅提高了便利性,而且提高了代码安全性。我一直在使用它。
    【解决方案3】:

    尝试使用System.Diagnostics.StackTrace 反映调用堆栈。该属性应位于调用堆栈中的某个位置(如果您直接从该属性的代码中调用它,则可能位于顶部)。

    【讨论】:

      【解决方案4】:

      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 倍。

      【讨论】:

        【解决方案5】:

        我想更多地了解您需要它的上下文,因为在我看来,您应该已经知道您在属性访问器中使用的属性。但是,如果必须,您可以使用MethodBase.GetCurrentMethod().Name 并删除get_/set_ 之后的任何内容。

        更新

        根据您的更改,我会说您应该使用继承而不是反射。我不知道您的字典中有哪些数据,但在我看来,您确实希望拥有不同的 Car 类,例如 Sedan、Roadster、Buggy、StationWagon,而不是将类型保存在局部变量中。然后,您将拥有为该类型的 Car 执行正确操作的方法的实现。无需找出您拥有的汽车类型,然后执行某项操作,您只需调用适当的方法,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...
               }
         }
        

        【讨论】:

        • 我添加了更多关于我的上下文的解释。
        • 您的更新只是说明了为什么您不应该尝试使用反射。使用建议的反射方式,您最终可能会发现您在“GetThisPropertyName”中,并决定您是“ThisPropertyName”属性。您将不得不调整示例以“向下”进行一次堆栈调用,以便获得实际的属性调用。虽然有可能,但它看起来有点矫枉过正。您的代码将洒满 this[GetThisPropertyName()] 调用的复制/粘贴,并且不再可读(恕我直言)。我个人会坚持使用普通的字符串 dict 访问器。
        【解决方案6】:

        由于属性实际上只是方法,因此您可以执行此操作并清理返回的 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 缓慢的有趣讨论可以是 found here

        如果您担心性能,我想另一种选择是创建一个 Visual Studio Intellisense 代码片段,它为您创建属性并创建一个与属性名称对应的字符串。

        【讨论】:

        • 有趣——我不知道 GetCurrentMethod()
        • Properties 你有类似的吗?
        【解决方案7】:

        改用 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_","");
            }
        

        【讨论】:

        • 我一直在做这样的事情,但它让我又回来了。请注意,如果内联属性可能会导致问题:将 [MethodImpl(MethodImplOptions.NoInlining)] 放在 getter/setter 之前会有所帮助,但不方便......
        【解决方案8】:

        是的!

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

        【讨论】:

          猜你喜欢
          • 2012-05-23
          • 1970-01-01
          • 2014-01-30
          • 2013-07-18
          • 1970-01-01
          • 2011-10-02
          • 2020-09-15
          • 2023-03-28
          • 2012-09-01
          相关资源
          最近更新 更多