4

switch ステートメントのケース数をカウントする C# メソッドが必要です。( と呼びましょうCaseCounter)。たとえば、この列挙型と次の 2 つのメソッドがあるとします。

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

ここで、次の等式が成り立つはずです。

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

(カウントにデフォルトのケースを含めるかどうかは重要ではありません。また、パラメータ toCaseCounterは文字列である必要はありません。メソッドを表すために何らかの形で使用できる型であれば何でもかまいません。)

では、どのように実装しCaseCounterますか? それは可能ですか?

--- 補遺 (編集) ---

なぜ私がこの質問をしたのか疑問に思っている方のために、ここに少し背景情報を示します。

列挙型をオンにする多くのメソッドを含むコード ベースを維持しています。メソッドはさまざまなクラスに分散しています。これにより、列挙型が拡張された場合 (たとえば、新しい を追加した場合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);
}

(この例では、 は列挙型の 5 つの可能な値すべてを明示的に参照IsModernAllCasesする単なるバリエーションです。)IsModernPainter

このテストは何もないよりはましですが、扱いにくいです。次のように書くことができれば、少しぎこちなくなります。

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

このシナリオでは、少なくとも、列挙型を拡張するときに単体テストを変更する必要はありません。

4

4 に答える 4

5

Microsoft のサービスとしてのコンパイラのプレリリース製品である Roslyn CTPを使用できるはずです。C# コードを検査し、それを命令のツリーとして表現できるようにする API があります。残念ながら、これは CTP であり、問​​題になる場合とそうでない場合があります。使用しようとする場合は、リリース前のソフトウェアであることを覚えておいてください。

Roslyn を使用できない場合は、生成された IL を検査するしか方法はないと思います。控えめに言っても、大変な作業です。そのためのサンプル コードはありませんが、試してみたい場合は、IL を検査するための API がいくつかあるCecil Mono プロジェクトを調べることから始めます。

生の IL バイトを取得し、それらのバイトを自分で解析することもできMethodInfo.GetMethodBodyますが、そのためにはいくつかの作業が必要です。

また、この関連する質問も参照してください。

于 2012-08-30T19:18:20.283 に答える
4

これは Reflection 経由では実行できませんが、Roslyn CTP経由で実行できます。Roslyn は、ソース コード自体を分析し、それに関する情報を判断するために必要なツールを提供します。このコードのツリーをたどって、switch ステートメントを含むメソッドを見つけ、個々のケースを数えることができます。

于 2012-08-30T19:17:43.920 に答える
3

あなたがこれをしている理由を知らずに、これがあなたにとって受け入れられるアプローチであるかどうかを知ることは難しいです。

これらのC#ファイルは基本的にコンピューター上の単なるテキストファイルであるため、すべてのファイルをループする別のアプリケーションを作成できます。caseメソッドを認識し、 (コメントではない)単語の出現回数を数え、結果を報告する必要があります。

現在、この機能を実行時にアプリ内で実行する必要がある場合、このアプローチは機能しません。

于 2012-08-30T19:31:55.673 に答える
0

Visual Studioでケースワードを検索して、リファクタリングを行うだけで十分です。

于 2012-08-30T19:32:05.263 に答える