views:

95

answers:

5

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

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.

Nathan Taylor
No, this doesn't work for me. I added your snippet to my console test app, but the foreach loop only returns 'Chars' and 'Length' for the .Name property. I need to get back 'MyResources.TOKEN_ONE'I used the following syntax:foreach (var propInfo in MyResources.TOKEN_ONE.GetType().GetProperties())...
Armchair Bronco
+1  A: 

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));
JaredPar
I should have specified in the OP that I don't want to enumerate *all* of the static properties in a given class, just a very small subset that I'm interested in. I'll clarify this with a longer post below.
Armchair Bronco
The real-world scenario is that I have an auto-generated C# WebResources class that consists of every single RESX string token in my webapp. There are thousands of strings in the RESX file (and in the generated class). For any given page, however, there may only be 2 or 3 TOKENS that are used in a scripting context. Maybe I want to use the token in a JavaScript alert().
Armchair Bronco
So, if in C# I know that I want to use the *value* for the resource token MyResources.TOKEN_ONE, I'd also like to have a way to get at the *name* of that specific static class property.How can I tell C# : "Give me the string name of the static property that's called MyResources.TOKEN_ONE". It should then return "MyResources.TOKEN_ONE". Then I can split this string and use "TOKEN_ONE" as the JavaScript variable name for the token.
Armchair Bronco
Your code does a great job of digging through everything (thanks). But what if I just want the .Name property for a single static property?
Armchair Bronco
A: 

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

Armchair Bronco
I think my second answer provides a solution to what you are lamenting here.
Timwi
Yes, the second time around was what the doctor ordered. Thanks again. I've already marked that reply as the answer to this thread.
Armchair Bronco
A: 

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;
}
Timwi
Yes, attributes are one way of flagging items I want, but in my case, the underlying class is generated by the .NET framework itself. So, I don't have the option of adding attributes of any sort. The preamble to the resources class reads: "This code was generated by a tool...Changes to this file may cause incorrect behavior and will be lost if the code is regenerated."
Armchair Bronco
More specifically, the class is the internal WebResources class that's paired up with my RESX file (in the App_GlobalResources directory).
Armchair Bronco
A: 

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);
}
Timwi
Awesome! This code does *EXACTLY* what I needed. I've already integrated it into my project. Thanks so much for your help, and thanks to the other respondents, too. I apologize for not doing a better of explaining up-front what I was trying to achieve. They say to be careful what you wish for. I've gotten rid of hard-coded string literals, but now I'm using unfamiliar code in my web application. Guess it's time to hit the book and learn about lambda expressions and expression trees! Thanks again.
Armchair Bronco