2009-07-30 102 views
35

我想通过反射机制获取属性名称。可能吗?如何通过反射获取当前属性名称?

更新: 我有这样的代码:

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

+1我也想到了这个实施System.Configuration.ApplicationSettingsBase – 2009-07-30 12:24:26

回答

47

由于属性是真的只是方法可以做到这一点,清理的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智能感知代码片段,为您创建属性并创建与属性名称对应的字符串。

0

是的,它是!

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

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

5

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

时,我一直在做这样的事情,它抓住了我。请注意,如果属性被内联,可能会导致问题:将[MethodImpl(MethodImplOptions.NoInlining)]放在getter/setter之前,但它很不方便。 – 2012-02-08 13:44:22

6

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

更新:根据您的更改

,我会说,你应该使用继承,而不是反射。我不知道你的字典中有什么数据,但在我看来,你真的想要有不同的汽车类别,比如轿车,敞篷跑车,越野车,旅行车,而不是将类型保存在本地变量中。然后你就可以实现那些为这种类型的车做适当的事情的方法。你不用找出你有什么样的车,然后做一些事情,然后简单地调用适当的方法,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... 
     } 
} 
+0

更多示例在:http://www.codeproject.com /KB/dotnet/MethodName.aspx – 2009-07-30 11:43:18

+0

我已经添加了一些关于我的上下文的更多解释。 – 2009-07-30 11:46:17

+0

您的更新只是说明为什么你不应该尝试使用反射。使用建议的反射方式,您可能最终会发现您位于“GetThisPropertyName”内部,并决定您重新使用“ThisPropertyName”属性。你将不得不调整这个例子去“下”一个堆栈调用,以获得实际的属性调用。虽然这是可能的,但看起来像是过度杀伤力。您的代码将被复制/粘贴[GetThisPropertyName()]调用,并且不会更具可读性(恕我直言)。我会坚持使用普通字符串字典访问器,个人。 – 2009-07-30 11:57:57

3

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>(); 

但它比上面的版本600X慢。

3

你提出的有点混乱的例子,除非我不明白。 从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; 
} 
相关问题