3

Here's a contrived example of a string literal switch statement:

static string GetStuff(string key)
{
    switch (key)
    {
        case "thing1": return "oh no";
        case "thing2": return "oh yes";
        case "cat": return "in a hat";
        case "wocket": return "in my pocket";
        case "redFish": return "blue fish";
        case "oneFish": return "two fish";
        default: throw new NotImplementedException("The key '" + key + "'  does not exist, go ask your Dad");
    }
}

You get the idea.

What I'd love to do is print each of the literal strings for each of the cases via reflection.

I've not done enough with reflection to know how to do it intuitively. I'm honestly not sure if reflection can do this kind of thing at all.

Can it be done? If so, how?

OneHoopyFrood
  • 3,829
  • 3
  • 24
  • 39
  • 1
    Reflection is for looking at object information i.e. classes, properties, methods, etc. Code inside those things cannot be reflected. Look into the Visitor Pattern: http://en.wikipedia.org/wiki/Visitor_pattern – TyCobb Nov 05 '14 at 00:15
  • 1
    Unfortunately, the linked Q&A doesn't clarify here. It's still not clear what you mean by "initialized at compile time", and the answer given in that link specifically points out what I mentioned earlier, which is that if you have enough `case` labels (IIRC, the threshold is seven or more) the code just gets turned into a dictionary anyway. What are you trying to achieve here that you cannot with an actual dictionary? – Peter Duniho Nov 05 '14 at 00:23
  • I didn't know about that functionality. I was just looking for a const Dictionary at the time. The question though was weather I could get to these via Reflection or not. That's all I really needed to know. I know Dictionaries are the way to go and due to your advice I'll switch to that mechanism. – OneHoopyFrood Nov 05 '14 at 00:25
  • But what do you mean by "const Dictionary"? What, _specifically_, do you hope to gain? If you are concerned about runtime initialization overhead, then a `switch` statement doesn't solve that (large switches are implemented as run-time-initialized dictionaries!). If you just don't want any other code to be able to modify the dictionary, then see the [`ReadOnlyDictionary`](http://msdn.microsoft.com/en-us/library/gg712875(v=vs.110).aspx) class – Peter Duniho Nov 05 '14 at 00:31

2 Answers2

5

No, you can't read IL (which is what you are looking for) with Reflection APIs.

The closest you can come is MethodInfo.GetMethodBody (MethodBody class) which will give you byte array with IL. To get implementation details of method you need library that reads IL like cecil.

The switch for string is implemented using if or Dictionary based on number of choices - see Are .Net switch statements hashed or indexed?. So if reading IL take that into account.*

Note that you should use some other mechanisms to represent your data rather that trying to read it from compiled code. I.e. use dictionary to represent choices as suggested by MikeH's answer.

* info on switch implementation found by Mad Sorcerer.

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • This is what I was wondering. I agree the other method is a better way to store the information. But that's not what I was asking. – OneHoopyFrood Nov 05 '14 at 00:21
  • 1
    @colepanike Not the simplest task. Refer [this](http://stackoverflow.com/questions/3366376/are-net-switch-statements-hashed-or-indexed) to see some details of IL `switch` implementation. I would use a `Dictionary` instead of parsing method's body. – Diligent Key Presser Nov 05 '14 at 01:13
2

How about using a Dictionary

  Dictionary<string, string> dict = new Dictionary<string, string>();
  dict.Add("thing1", "oh no");
  dict.Add("thing2", "oh yes");
  //and on and on

  string GetStuff(string key)
  {
    if (dict.ContainsKey(key))
      return dict[key];
    else
      return null; //or throw exception
  }

For your menu:

 void addToMenu()
 {
   foreach (string key in dict.Keys)
   {
     //add "key" to menu
   }

 }
MikeH
  • 4,242
  • 1
  • 17
  • 32
  • You could even use the shorter initalizer syntax: `new Dictionary { { "thing1", "oh no" }, { "thing2", "oh yes" } }` and `TryGetValue` – Lucas Trzesniewski Nov 05 '14 at 00:15
  • The reason I'm not using a dictionary is the compile-time constraint. I chose this admittedly rather ugly syntax because a `Dictionary` can't be made at compile time. – OneHoopyFrood Nov 05 '14 at 00:15
  • @LucasTrzesniewski Very true. I was going for clarity though. – MikeH Nov 05 '14 at 00:16
  • 2
    @colepanike can you explain your compile time constraint? – MikeH Nov 05 '14 at 00:16
  • 1
    @colepanike Just store your dictionary in a `static` field, and use the initializer syntax to init it. – Lucas Trzesniewski Nov 05 '14 at 00:16
  • 3
    @colepanike: what do you mean by "compile-time constraint"? How does your `switch` statement qualify as a "compile-time dictionary"? It's not like you can execute the code at compile-time. Also, are you aware that when `string` values are used for `case` labels in a `switch` statement, that the C# compiler will turn that into a run-time-initialized dictionary on your behalf (for `switch` statements with more than a few cases...otherwise the `switch` is implemented as a series of `if`/`else if`/`else` statements). – Peter Duniho Nov 05 '14 at 00:19
  • I agree, this is better and cleaner. But it's not what I'm asking. I wanted to know if reflection could get at these values. Thanks for your input though! – OneHoopyFrood Nov 05 '14 at 00:21