计算switch语句中的个案数

use*_*813 4 c# counting switch-statement

我想有一个C#方法来计算交换机语句中的案例数.(我们称之为CaseCounter).例如,假设你有这个枚举和这两种方法:

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;
     }
}
Run Code Online (Sandbox Code Playgroud)

现在应该保持以下平等:

CaseCounter("GetYearOfBirth") == 5
CaseCounter("IsModern") == 2
Run Code Online (Sandbox Code Playgroud)

(在计数中是否包含默认大小写并不重要.此外,参数CaseCounter不需要是字符串;任何可以某种方式用于表示方法的类型都可以.)

那么,你将如何实施CaseCounter?它甚至可能吗?

--- ADDENDUM(编辑)---

这里有一些背景信息,如果你想知道为什么我问这个问题.

我正在维护一个代码库,其中包含很多打开枚举的方法.这些方法分布在各个类别中; 当枚举枚举时(例如,当你添加一个新的Painter)时,这会使生活变得困难.为了使维护更容易,我已经编写了以下形式的单元测试:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

(在这个例子中,IsModernAllCases只是一个变体IsModern明确地引用了Painter枚举的所有5个可能的值.)

这个测试总比没有好,但它很笨拙.如果你能写出这样的东西,那就不那么笨拙了:

[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);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,至少在扩展枚举时不必修改单元测试.

dri*_*iis 5

应该可以使用Roslyn CTP - Microsoft的编译器即服务预发布产品.它具有API,可让您检查C#代码并将其表示为指令树.不幸的是,它是一个CTP,对你来说可能是也可能不是问题 - 只要记住它是预发布软件,如果你试图使用它.

如果您不能使用Roslyn,我认为唯一的方法是检查生成的IL.至少可以说是一项艰巨的任务.我没有任何示例代码,但如果你想尝试一下 - 我会先看一下Cecil Mono项目,它有一些用于检查IL的API.

您还MethodInfo.GetMethodBody可以获取原始IL字节,然后自己解析这些字节,但它确实需要一些工作才能完成.

另外,请参阅此相关问题.

  • 我已经做了.在我的测试中,单例`switch`语句编译成一个简单的条件分支.四个`switch`语句编译成一个实际的IL`witch`指令.所以@ driis使用`GetMethodBody`的答案并不总能找到这些.(Code和IL at http://pastebin.com/97s4siKN) (2认同)