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

时间:2009-07-30 11:32:37

标签: c# reflection properties

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

更新: 我有这样的代码:

    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 个答案:

答案 0 :(得分:51)

由于属性实际上只是方法,因此您可以执行此操作并清理返回的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 Code Snippet,为您创建属性,并创建一个与属性名称对应的字符串。

答案 1 :(得分:7)

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

<强>更新

根据您的更改,我会说您应该使用继承而不是反射。我不知道你的词典里有什么数据,但在我看来你真的想拥有不同的Car类,比如Sedan,Roadster,Buggy,StationWagon,不要把类型保存在局部变量中。然后你会有方法的实现,为那种类型的汽车做正确的事情。然后你可以简单地调用适当的方法而不是找出你拥有的汽车类型,然后根据它的类型来调用适当的方法。

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

答案 2 :(得分:5)

改为使用MethodBase.GetCurrentMethod()

Reflection用于处理在编译时无法完成的类型。获取您所在的属性访问者的名称可以在编译时决定,因此您可能不应该使用反射。

您可以使用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 :(得分:5)

你提出的一个有点混乱的例子,除非我没有得到它。 从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;
}  

答案 4 :(得分: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>();

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

答案 5 :(得分: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;
}

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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