How can I get the name of a C# static class proper

2020-02-07 05:13发布

问题:

I want to make a C# Dictionary in which the key is the string name of a static property in a class and the value is the value of the property. Given a static property in the class called MyResources.TOKEN_ONE, how can I get the at the name of the property rather than its value? I only care about the end part of the property name (e.g. "TOKEN_ONE").

I've edited this to mention that I don't want to map all property values in the Dictionary, just a small subset of everything that's in the class. So assume that I want to get the name for a single property. Given MyResources.TOKEN_ONE, I want to get back "MyResources.TOKEN_ONE" or just "TOKEN_ONE".

Here's some sample code that shows what I'm trying to do. I need the property name because I'm trying to generate a javascript variable in which I map the property name to the variable name and the property value to the variable value. For example, I want the C# Dictionary to generate lines like the one below:

var TOKEN_ONE = "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"; }
      }
   }
}

回答1:

If all you want is just to be able to refer to a single, specific property in one place in the code without having to refer to it by a literal string, then you can use an expression tree. For example, the following code declares a method that turns such an expression tree into a PropertyInfo object:

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

Now you can do something like this:

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:

Here is a function that will get you the names of all static properties in a given type.

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

If you want to build up the map of all property names to their values you can do the following

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

Now you can call it with the following

var bag = GetStaticPropertyBag(typeof(MyResources));


回答3:

You can accomplish this with reflection. The easiest way to get the property names is to loop over all of them.

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

See GetProperties() and GetValue() for more specifics.



回答4:

Well, I'm reluctantly answering my own question because I don't think it's possible to do this for a single static property. Ultimately, I ended up hard-coding the key in the Dictionary using a cut-and-paste of the property name. Here's what I ended up with:

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

And here's the rest of the code:

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

I hate having to use cut-and-paste hard-coding to keep the property name and the key in sync...Oh well...



回答5:

Other answers have already explained how you can get a list of the static properties via Reflection. You said you don’t want all of them, only a subset of them. It seems, therefore, that you need a way to distinguish the properties you want from the ones you don’t want. One way to do this is using custom attributes.

Declare a custom attribute class:

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

Add this custom attribute to the properties you want:

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

Iterate over the properties to find the ones you want:

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