【问题标题】:Why is the cyclomatic complexity of an event 2?为什么事件的圈复杂度是 2?
【发布时间】:2017-08-18 21:52:02
【问题描述】:

我正在检查应用程序中的圈复杂度,目的是测试任何圈复杂度大于 1 的事物。

我看到的是一个非常简单的事件的 add 访问器的圈复杂度为 2。这是为什么呢?是不是因为add方法先检查回调方法是否已经注册?

我创建了一个非常简单的计算器应用程序来复制这种行为。我有一个名为 CalculateComplete 的事件,它会在 Calculate() 方法完成时触发。

【问题讨论】:

    标签: c# events code-metrics cyclomatic-complexity


    【解决方案1】:

    如果有一些类有一些事件,例如

    class SomeClass
    {
        public event Action<int> SomeEvent;
    }
    

    那么为事件添加方法生成的IL代码为:

    SomeClass.add_SomeEvent:
    IL_0000:  ldarg.0     
    IL_0001:  ldfld       UserQuery+SomeClass.SomeEvent
    IL_0006:  stloc.0     
    IL_0007:  ldloc.0     
    IL_0008:  stloc.1     
    IL_0009:  ldloc.1     
    IL_000A:  ldarg.1     
    IL_000B:  call        System.Delegate.Combine
    IL_0010:  castclass   System.Action<System.Int32>
    IL_0015:  stloc.2     
    IL_0016:  ldarg.0     
    IL_0017:  ldflda      UserQuery+SomeClass.SomeEvent
    IL_001C:  ldloc.2     
    IL_001D:  ldloc.1     
    IL_001E:  call        System.Threading.Interlocked.CompareExchange<Action`1>
    IL_0023:  stloc.0     
    IL_0024:  ldloc.0     
    IL_0025:  ldloc.1     
    IL_0026:  bne.un.s    IL_0007
    IL_0028:  ret
    

    请注意,在方法的末尾有一个Interlocked.CompareExchange() 调用,后跟一个“如果不相等则分支”。所以是的,有一个分支,因此圈复杂度为 2。

    你可能会问为什么会这样?原因是委托是不可变的。当您向委托添加方法时,您不会修改原始委托,而是实际上从现有委托和提供的方法创建组合委托,并将其重新分配给事件。见Delegate.Combine

    除此之外,新旧委托之间的交换必须是线程安全的,这就是Interlocked.CompareExchange 的原因。如果交换失败,请重试。

    为了提供帮助,我已将 IL 翻译成 C#:

    public void add_SomeEvent(Action<int> arg1)
    {
        var local0 = this.SomeEvent;
    IL_0007:
        var local1 = local0;
        var local2 = (Action<int>)Delegate.Combine(local1, arg1);
        local0 = Interlocked.CompareExchange(ref this.SomeEvent, local2, local1)
        if (local0 != local1) goto IL_0007;
    }
    

    【讨论】:

    • 要真正将其翻译成 C#,那就是 do...while 循环。
    • 是的,这将是一个do..while 循环。但是标签和gotos 也是有效的 C#,我想让它尽可能类似于 IL。
    猜你喜欢
    • 2010-10-29
    • 2012-10-29
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 2013-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多