簡體   English   中英

如何使用反射獲取C#靜態類屬性的名稱?

[英]How can I get the name of a C# static class property using reflection?

我想制作一個C#詞典,其中的鍵是類中靜態屬性的字符串名稱,而值是該屬性的值。 給定名為MyResources.TOKEN_ONE的類中的靜態屬性,如何獲取屬性名稱而不是其值? 我只關心屬性名稱的結尾部分(例如“ TOKEN_ONE”)。

我進行了編輯,以提及我不想映射Dictionary中的所有屬性值,而只是映射類中所有內容的一小部分。 因此,假設我要獲取單個屬性的名稱。 給定MyResources.TOKEN_ONE,我想找回“ MyResources.TOKEN_ONE”或“ TOKEN_ONE”。

這是一些示例代碼,顯示了我要執行的操作。 我需要屬性名稱,因為我試圖生成一個JavaScript變量,在其中將屬性名稱映射到變量名稱,並將屬性值映射到變量值。 例如,我希望C#詞典生成類似於以下內容的行:

var TOKEN_ONE =“一個”;

using System;
using System.Collections.Generic;

namespace MyConsoleApp
{
   class Program
   {
      static void Main(string[] args)
      {
         Dictionary<String, String> kvp = new Dictionary<String, String>();

         // How can I use the name of static property in a class as the key for the dictionary?
         // For example, I'd like to do something like the following where 'PropertyNameFromReflection'
         // is a mechanism that would return "MyResources.TOKEN_ONE"
         kvp.Add(MyResources.TOKEN_ONE.PropertyNameFromReflection, MyResources.TOKEN_ONE);
         kvp.Add(MyResources.TOKEN_TWO.PropertyNameFromReflection, MyResources.TOKEN_TWO);

         Console.ReadLine();
      }
   }

   public static class MyResources
   {
      public static string TOKEN_ONE
      {
         get { return "One"; }
      }

      public static string TOKEN_TWO
      {
         get { return "Two"; }
      }
   }
}

如果只需要能夠在代碼中的一個位置引用單個特定屬性, 不必通過文字字符串來引用它,則可以使用表達式樹。 例如,以下代碼聲明了一個將這樣的表達式樹轉換為PropertyInfo對象的方法:

public static PropertyInfo GetProperty(Expression<Func<string>> expr)
{
    var member = expr.Body as MemberExpression;
    if (member == null)
        throw new InvalidOperationException("Expression is not a member access expression.");
    var property = member.Member as PropertyInfo;
    if (property == null)
        throw new InvalidOperationException("Member in expression is not a property.");
    return property;
}

現在您可以執行以下操作:

public void AddJavaScriptToken(Expression<Func<string>> propertyExpression)
{
    var p = GetProperty(propertyExpression);
    _javaScriptTokens.Add(p.Name, (string) p.GetValue(null, null));
}

public void RegisterJavaScriptTokens()
{
    AddJavaScriptToken(() => Tokens.TOKEN_ONE);
    AddJavaScriptToken(() => Tokens.TOKEN_TWO);
}

這是一個函數,它將為您提供給定類型的所有靜態屬性的名稱。

public static IEnumerable<string> GetStaticPropertyNames(Type t) {
  foreach ( var prop in t.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ) {
    yield return prop.Name; 
  }
}

如果要建立所有屬性名稱到它們的值的映射,可以執行以下操作

public static Dictionary<string,object> GetStaticPropertyBag(Type t) {
  var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
  var map = new Dictionary<string,object>();
  foreach ( var prop in t.GetProperties(flags) ) {
    map[prop.Name] = prop.GetValue(null,null);
  }
  return map;
}

現在您可以使用以下命令調用它

var bag = GetStaticPropertyBag(typeof(MyResources));

您可以通過反射來實現。 獲取屬性名稱的最簡單方法是遍歷所有屬性。

foreach(var propInfo in this.GetType().GetProperties()) {
    var name = propInfo.Name;
    var value = propInfo.GetValue(this, null);
}

有關更多詳細信息,請參見GetProperties()GetValue()

好吧,我無奈地回答了我自己的問題,因為我認為不可能對單個靜態屬性執行此操作。 最終,我最終使用屬性名稱的剪切粘貼功能在“字典”中對密鑰進行了硬編碼。 我最終得到的是:

  public void RegisterJavaScriptTokens()
  {
     AddJavaScriptToken(Token.FOOBAR_TITLE, "FOOBAR_TITLE"); 
  }

這是其余的代碼:

  protected Dictionary<String, String> _javaScriptTokens = new Dictionary<String, String>();

  public void AddJavaScriptToken(string tokenValue, string propertyName)
  {
     _javaScriptTokens.Add(propertyName, tokenValue);
  }

  protected override void OnPreRender(EventArgs e)
  {
     if (_javaScriptTokens.Count > 0)
     {
        StringBuilder sb = new StringBuilder();

        foreach (KeyValuePair<String, String> kvp in _javaScriptTokens)
        {
           sb.AppendLine(String.Format("var TOKEN_{0} = unescape('{1}');", kvp.Key, PUtilities.Escape(kvp.Value)));
        }

        ClientScript.RegisterStartupScript(this.GetType(), "PAGE_TOKENS", sb.ToString(), true);
     }

     base.OnPreRender(e);
  }

我討厭不得不使用剪切和粘貼硬編碼來使屬性名稱和密鑰保持同步...哦...

其他答案已經解釋了如何通過反射獲得靜態屬性列表。 您說過,您不想要所有這些,而只是其中的一部分。 因此,似乎需要一種方法來區分所需的屬性和不需要的屬性。 一種方法是使用自定義屬性。

聲明一個自定義屬性類:

[AttributeUsage(AttributeTargets.Property)]
public class WantThisAttribute : Attribute { }

將此自定義屬性添加到所需的屬性中:

public static class MyResources
{
    [WantThis]
    public static string TOKEN_ONE { get { return "One"; } }

    [WantThis]
    public static string TOKEN_TWO { get { return "Two"; } }

    public static string DontWantThis { get { return "Nope"; } }
}

遍歷屬性以查找所需屬性:

public static Dictionary<string, object> GetStaticPropertyBag(Type t)
{
    var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
    var map = new Dictionary<string, object>();
    foreach (var prop in t.GetProperties(flags))
        if (prop.IsDefined(typeof(WantThisAttribute), true))
            map[prop.Name] = prop.GetValue(null,null);
    return map;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM