简体   繁体   English

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

[英]How to get current property name via reflection?

I would like to get property name when I'm in it via reflection mechanism. 我想通过反射机制获取属性名称。 Is it possible? 可能吗?

Update: I have code like this: 更新:我有这样的代码:

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

And because I need more properties like this I would like to do something like this: 因为我需要更多这样的属性,我想做这样的事情:

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

Since properties are really just methods you can do this and clean up the get_ returned: 由于属性实际上只是方法,您可以执行此操作并清理返回的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;
            }
        }
    }

If you profile the performance you should find MethodBase.GetCurrentMethod() is miles faster than StackFrame. 如果您对性能进行了分析,则应该找到MethodBase.GetCurrentMethod()比StackFrame快几英里。 In .NET 1.1 you will also have issues with StackFrame in release mode (from memory I think I found it was 3x faster). 在.NET 1.1中,你也会在发布模式下遇到StackFrame的问题(从内存中我发现它发现它快了3倍)。

That said I'm sure the performance issue won't cause too much of a problem- though an interesting discussion on StackFrame slowness can be found here . 这就是说我确信性能问题不会引起太多问题 - 尽管可以在这里找到有关StackFrame慢度的有趣讨论。

I guess another option if you were concerned about performance would be to create a Visual Studio Intellisense Code Snippet that creates the property for you and also creates a string that corresponds to the property name. 我想如果您担心性能,另一个选择是创建一个Visual Studio Intellisense代码片段,为您创建属性,并创建一个与属性名称对应的字符串。

I'd like to know more about the context in which you need it since it seems to me that you should already know what property you are working with in the property accessor. 我想知道更多关于你需要它的上下文,因为在我看来你应该已经知道你在属性访问器中使用了什么属性。 If you must, though, you could probably use MethodBase.GetCurrentMethod() .Name and remove anything after get_/set_ . 但是,如果必须,可以使用MethodBase.GetCurrentMethod()。 Name并在get_/set_之后删除任何内容。

Update : 更新

Based on your changes, I would say that you should use inheritance rather than reflection. 根据您的更改,我会说您应该使用继承而不是反射。 I don't know what data is in your dictionary, but it seems to me that you really want to have different Car classes, say Sedan, Roadster, Buggy, StationWagon, not keep the type in a local variable. 我不知道你的词典里有什么数据,但在我看来你真的想拥有不同的Car类,比如Sedan,Roadster,Buggy,StationWagon,不要把类型保存在局部变量中。 Then you would have implementations of methods that do the proper thing for that type of Car. 然后你会有方法的实现,为那种类型的汽车做正确的事情。 Instead of finding out what kind of car you have, then doing something, you then simply call the appropriate method and the Car object does the right thing based on what type it is. 然后你可以简单地调用适当的方法,而不是找出你拥有的汽车类型,然后根据它的类型做出合适的方法。

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

Slightly confusing example you presented, unless I just don't get it. 你提出的例子有点令人困惑,除非我没有得到它。 From C# 6.0 you can use the nameof operator. 从C#6.0开始,您可以使用nameof运算符。

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

If you have a method that handles your getter/setter anyway, you can use the C# 4.5 CallerMemberName attribute, in this case you don't even need to repeat the name. 如果你有一个方法来处理你的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;
}  

Use MethodBase.GetCurrentMethod() instead! 请改用MethodBase.GetCurrentMethod()!

Reflection is used to do work with types that can't be done at compile time. 反射用于处理在编译时无法完成的类型。 Getting the name of the property accessor you're in can be decided at compile time so you probably shouldn't use reflection for it. 获取您所在的属性访问者的名称可以在编译时决定,因此您可能不应该使用反射。

You get use the accessor method's name from the call stack using System.Diagnostics.StackTrace though. 您可以使用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_","");
    }

FWIW I implemented a system like this: 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;
        }

There's also a custom attribute class called CrmAttributeAttribute. 还有一个名为CrmAttributeAttribute的自定义属性类。

I'd strongly recommend against using GetStackFrame() as part of your solution, my original version of the solution was originally the much neater: 我强烈建议不要使用GetStackFrame()作为解决方案的一部分,我原来的解决方案版本最初更整洁:

return GetPropValue<string>();

But it was 600x slower than the version above. 但它比上面的版本慢600倍。

Yes, it is! 是的!

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

Try using System.Diagnostics.StackTrace to reflect on the call stack. 尝试使用System.Diagnostics.StackTrace来反映调用堆栈。 The property should be somewhere in the call stack (probably at the top if you're calling it directly from the property's code). 该属性应该位于调用堆栈中的某个位置(如果您直接从属性的代码中调用它,则可能位于顶部)。

Way # 1 方式#1

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

Way # 2 方式#2

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

Way # 3 方式#3

from StackTrace: 来自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;
}

you just need to call Props.CurrPropName or Props.CurrMethodName 你只需要调用Props.CurrPropNameProps.CurrMethodName


Way # 4 方式#4

Solution for .NET 4.5+: .NET 4.5+的解决方案:

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

usgae: Props.GetCallerName(); usgae: Props.GetCallerName();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM