如何通过反射获取当前属性名称?

Posted

技术标签:

【中文标题】如何通过反射获取当前属性名称?【英文标题】: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 时也想知道这个 【参考方案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;

【讨论】:

以上是关于如何通过反射获取当前属性名称?的主要内容,如果未能解决你的问题,请参考以下文章

java中如何通过反射获取类的属性

说说对java反射的理解,使用反射如何获取一个类的所有方法,使用反射需要注意哪些问题?

C#通过反射获取不同命名空间下的类(属性和方法)

c# 如何通过反射 获取属性值

java如何通过反射获取包中所有的类?

C# 反射之属性操作