4

I would like to have a C# method which counts the number of cases in a switch statment. (Let's call it CaseCounter). For example, let's say you have this enum and these two methods:

enum Painter  
{  
    Rubens,  
    Rembrandt,  
    Vermeer,
    Picasso,
    Kandinsky
}

int GetYearOfBirth(Painter painter)
{
    switch(painter)
    {
        case Painter.Kandinsky:
            return 1866;    
        case Painter.Picasso:
            return 1881;
        case Painter.Rembrandt:
            return 1606;
        case Painter.Rubens:
            return 1577;
        case Painter.Vermeer:
            return 1632;
        default:
            return 0;
    }
}

bool IsModern(Painter painter)
{
    switch (painter)
    {
        case Painter.Kandinsky:
        case Painter.Picasso:
            return true;
        default:
            return false;
     }
}

Now the following equalities should hold:

CaseCounter("GetYearOfBirth") == 5
CaseCounter("IsModern") == 2

(It is not important whether or not you include the default case in the count. Also, the parameter to CaseCounter doesn't need to be a string; any type which can somehow be used to represent a method will do.)

So, how would you go about implementing CaseCounter? Is it even possible?

--- ADDENDUM (EDIT) ---

Here's a bit of background info in case you're wondering why I asked this question.

I'm maintaining a code base which contains a lot of methods that switch on enums. The methods are spread across various classes; this makes life difficult when an enum is extended (for example, when you add a new Painter). To make maintenance a little bit easier, I have written some unit tests of the following form:

// If this test fails please check that the following methods are still OK: 
// MyClass.GetYearOfBirth, MyOtherClass.IsModernAllCases . 
// (There is no guarantee that the above list is up-to-date or complete.)
[Test]
public void PainterCountTest()
{
    int numberOfMembers = Enum.GetValues(typeof(NotificationID)).Length;
    Assert.AreEqual(5, numberOfMembers);
}

(In this example, IsModernAllCases is just a variation of IsModern which refers explicitly to all 5 possible values of the Painter enum.)

This test is better than nothing, but it's clumsy. It would be a little less clumsy if you could write something like this:

[Test]
public void PainterCountTest()
{
    int numberOfMembers = Enum.GetValues(typeof(NotificationID)).Length;

    int numberOfCases_getYearOfBirth = CaseCounter("MyClass.GetYearOfBirth");
    Assert.AreEqual(numberOfCases_getYearOfBirth, numberOfMembers);

    int numberOfCases_modern = CaseCounter("MyOtherClass.IsModernAllCases");
    Assert.AreEqual(numberOfCases_modern, numberOfMembers);
}

In this scenario, at least you don't have to modify the unit test when you extend the enum.

user181813
  • 1,861
  • 6
  • 24
  • 42

4 Answers4

5

It should be possible to do with the Roslyn CTP - Microsoft's compiler-as-a-service pre-release product. It has API's to let you inspect C# code and represent it as a tree of instructions. Unfortunately, it is a CTP, which may or may not be a problem for you - just remember it is pre-release software if you try to use it.

If you can't use Roslyn, I think the only way would be to inspect the generated IL. A daunting task, to say the least. I haven't got any sample code for that, but if you want to try it - I would start by looking at the Cecil Mono project, which has some API's for inspecting IL.

You could also MethodInfo.GetMethodBody to get the raw IL bytes and then parse those bytes yourself, but it does require some work to do that.

Also, see this related question.

Community
  • 1
  • 1
driis
  • 161,458
  • 45
  • 265
  • 341
  • 1
    Just out of curiosity: are the C# `switch` statements guaranteed to be compiled to the IL `switch`, or does the compiler have the option of using a simple conditional if the switch set is small? – Clinton Pierce Aug 30 '12 at 19:29
  • @clintp, I suspect `if` and `switch` might look the same in IL, though I am not sure. You could try compiling two methods and looking at them with ILSpy... – driis Aug 30 '12 at 19:31
  • 2
    I just did. And in my test, a single-case `switch` statement compiles down to a simple conditional branch. A four case `switch` statements compiles down to an actual IL `switch` instruction. So @driis's answer of using `GetMethodBody` won't always work to find these. (Code and IL at http://pastebin.com/97s4siKN ) – Clinton Pierce Aug 30 '12 at 19:42
4

This can't be done via Reflection, but could be done via the Roslyn CTP. Roslyn provides the tooling required to analyze the source code itself, and determine information about it. You could walk the trees in this code to find the methods containing switch statements, and make a count of individual cases.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
3

Without knowing why you are doing this, it's tough to know if this will be an acceptable approach for you.

Since these C# files are basically just text files on your computer, you could create a separate application that loops through all the files. It would need to recognize methods, count the number of occurrences of case words (that aren't comments), and report the results.

Now, if you need this functionality to run at runtime, within your app, then this approach won't work.

Bob Horn
  • 33,387
  • 34
  • 113
  • 219
0

make a find search in visual studio on your case word it is enough to make your refactoring

Hassan Boutougha
  • 3,871
  • 1
  • 17
  • 17