Как я могу получить имя свойства статического класса C #, используя отражение? - PullRequest
3 голосов
/ 21 августа 2010

Я хочу создать словарь C #, в котором ключ - это строковое имя статического свойства в классе, а значение - это значение свойства. Учитывая статическое свойство в классе с именем MyResources.TOKEN_ONE, как я могу получить имя свойства, а не его значение? Мне важна только конечная часть имени свойства (например, «TOKEN_ONE»).

Я отредактировал это, чтобы упомянуть, что я не хочу отображать все значения свойств в Словаре, просто небольшое подмножество всего, что находится в классе. Итак, предположим, что я хочу получить имя для одного свойства. Учитывая 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"; }
      }
   }
}

Ответы [ 5 ]

4 голосов
/ 21 августа 2010

Если все, что вам нужно, это просто иметь возможность ссылаться на одно конкретное свойство в одном месте кода без необходимости ссылаться на него литеральной строкой, тогда вы можете использовать дерево выражений , Например, следующий код объявляет метод, который превращает такое дерево выражений в объект 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);
}
2 голосов
/ 21 августа 2010

Вот функция, которая выдаст вам имена всех статических свойств данного типа.

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));
0 голосов
/ 21 августа 2010

Другие ответы уже объясняли, как вы можете получить список статических свойств с помощью Reflection. Вы сказали, что не хотите всех из них, только их подмножество. Поэтому кажется, что вам нужен способ отличить свойства, которые вы хотите, от свойств, которые вы не хотите. Одним из способов сделать это является использование пользовательских атрибутов.

Объявление класса пользовательских атрибутов:

[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;
}
0 голосов
/ 21 августа 2010

Ну, я неохотно отвечаю на свой вопрос, потому что не думаю, что это возможно сделать для одного статического свойства. В конечном итоге я жестко закодировал ключ в словаре, используя вырезанное и вставленное имя свойства. Вот что я закончил:

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

Я ненавижу использовать жесткое кодирование для вставки и вставки, чтобы синхронизировать имя свойства и ключ ... О, хорошо ...

0 голосов
/ 21 августа 2010

Вы можете сделать это с помощью отражения.Самый простой способ получить имена свойств - это перебрать их все .

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

См. GetProperties () и GetValue () для более подробной информации.

...