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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1206023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 10:53:47  来源:igfitidea点击:

How to get current property name via reflection?

c#reflectionproperties

提问by Tomasz Smykowski

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

采纳答案by RichardOD

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. In .NET 1.1 you will also have issues with StackFrame in release mode (from memory I think I found it was 3x faster).

如果您分析性能,您应该发现 MethodBase.GetCurrentMethod() 比 StackFrame 快几英里。在 .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 代码片段,为您创建属性并创建一个与属性名称相对应的字符串。

回答by Natrium

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

回答by BlueMonkMN

Try using System.Diagnostics.StackTraceto reflect on the call stack. The property should be somewhere in the call stack (probably at the top if you're calling it directly from the property's code).

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

回答by weiqure

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

您可以使用来自调用堆栈的访问器方法的名称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_","");
    }

回答by tvanfosson

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 并删除 .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. 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.

根据您的更改,我会说您应该使用继承而不是反射。我不知道您的字典中有哪些数据,但在我看来,您确实希望拥有不同的 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...
       }
 }

回答by stevieg

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

回答by Mike Fuchs

Slightly confusing example you presented, unless I just don't get it. From C# 6.0 you can use the nameofoperator.

你提出的例子有点令人困惑,除非我不明白。从 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 CallerMemberNameattribute, in this case you don't even need to repeat the name.

如果你有一个方法来处理你的 getter/setter,你可以使用 C# 4.5CallerMemberName属性,在这种情况下你甚至不需要重复名称。

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

回答by Andrew

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:

来自堆栈跟踪:

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

我们: Props.GetCallerName();