8

次のようなコードがあります。

private void InitializeEvents()
{
    this.Event1 += (s,e) => { };
    this.Event2 += (s,e) => { };
    this.Event3 += (s,e) => { };
    this.Event4 += (s,e) => { };
    this.Event5 += (s,e) => { };
    this.Event6 += (s,e) => { };
    this.Event7 += (s,e) => { };
    this.Event8 += (s,e) => { };
    this.Event9 += (s,e) => { };
    this.Event10 += (s,e) => { };
    this.Event11 += (s,e) => { };
    this.Event12 += (s,e) => { };
    this.Event13 += (s,e) => { };
}

VS10 Ultimate のコード分析では、「27 の循環的複雑度」と表示されます。行の 1 つを削除すると、循環的複雑度は 25 になります。

分岐が行われていないのに、どうしてこれが可能なのでしょうか?

4

3 に答える 3

17

コード分​​析は、ソース コードではなく、アセンブリ内の IL を調べていることに注意してください。ラムダ式をネイティブにサポートする IL には何もないため、ラムダ式はコンパイラの構成要素です。ここで出力される内容の詳細を確認できます。しかし、基本的にラムダ式は、匿名デリゲートであるプライベートな静的クラスに変換されます。ただし、コードで参照されるたびに匿名デリゲートのインスタンスを作成するのではなく、デリゲートがキャッシュされます。したがって、ラムダ式を割り当てるたびに、そのラムダ デリゲートのインスタンスが作成されているかどうかがチェックされます。作成されている場合は、キャッシュされたデリゲートが使用されます。これにより、IL で if/else が生成され、複雑さが 2 増加します。したがって、この関数の複雑さは 1 + 2*(lambda express) = 1 + 2 *(13) = 27 であり、これは正しい数値です。

于 2012-04-20T11:59:49.690 に答える
3

C# コンパイラは、ラムダを含む匿名メソッドに対してかなり「興味深い」IL を実際に生成します。それぞれに対してプライベート フィールドを作成し、その値をコンシューム メソッドに割り当てる前に、値が null かどうかをチェックします。これにより、If 分岐がコンパイル済みメソッドに追加されます。コード メトリクス ツールはこれを無視する必要があります ( http://social.msdn.microsoft.com/Forums/eu/vstscode/thread/8c17f569-5ee3-4d26-bf09-4ad4f9289705、https://connect.microsoft.com/VisualStudio /feedback/details/555560/method-using-many-lambda-expressions-causes-high-cyclomatic-complexity )、最終的にはそうなることを期待できます。今のところ、誤検知だと思われる場合は、問題をほとんど無視する必要があります。

于 2012-04-20T12:05:28.250 に答える
1

これはおそらく、上記のステートメントがイベント アクセサー形式に変換されたことが原因であると考えられます。

class MyClass
{
  private event EventHandler MyPrivateEvent;

  public event EventHandler MyEvent
  {
    add
    {
      MyPrivateEvent += value;
    }
    remove
    {
      MyPrivateEvent -= value;
    }
  }
}

イベント アクセサー形式の説明については、 http: //msdn.microsoft.com/en-us/magazine/cc163533.aspxおよびhttp://www.switchonthecode.com/tutorials/csharp-tutorial-event-accessorsを参照してください。

于 2012-04-20T10:11:11.420 に答える