2017-03-26 14 views
3

순환 적 복잡성이 1보다 큰 것을 테스트 할 목적으로 응용 프로그램에서 순환 복잡도를 면밀히 조사하고 있습니다.이벤트의 순환 복잡성이 왜 2입니까?

매우 간단한 이벤트의 접근 자의 순환 복잡도는 2입니다. 왜 이런거야? add 메소드가 콜백 메소드가 이미 등록되어 있는지 먼저 확인하기 때문입니까?

이 동작을 복제하는 매우 간단한 계산기 응용 프로그램을 만들었습니다. Calculate() 메서드가 완료되면 발생하는 CalculateComplete라는 이벤트가 있습니다.

enter image description here

답변

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

정말 C 번호로 번역하는, 그건 '... 할 while' 루프가 될 것입니다. –

+0

예, 'do..while' 루프가됩니다. 그러나 라벨과'goto's는 유효한 C#입니다. 가능한 한 일리노이와 비슷한 것으로두고 싶습니다. – vyrp