8

우리는 바콜,이 코드를 가지고 : VS10 궁극의이벤트 핸들러 구독이 13 개인 메서드에서 순환 복잡도가 27 일 수 있습니까?

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) => { }; 
} 

코드 분석 "(27)의 복잡성을"을 말한다. 라인 중 하나를 제거하면 순환 복잡성이 25가됩니다.

어떻게 진행 되나요?

답변

17

코드 분석에서 소스 코드가 아니라 어셈블리의 IL을보고 있다는 것을 기억하십시오. IL에서 기본적으로 람다 식을 지원하는 것은 없으므로 컴파일러의 구성 요소입니다. ouput here의 세부 사항을 찾을 수 있습니다. 하지만 기본적으로 람다 표현식은 익명의 deligate 인 개인 정적 클래스로 변환됩니다. 그러나 코드에서 참조 될 때마다 익명 deligate의 인스턴스를 만드는 대신 deligate가 캐시됩니다. 따라서 람다 식을 지정할 때마다 람다의 인스턴스가 만들어 졌는지 확인하는 검사가 수행됩니다.이 경우 캐시 된 deligate가 사용됩니다. 그것은 IL에서 if/else를 생성하여 복잡성을 2만큼 증가시킵니다. 따라서이 함수에서 복잡성은 1 + 2 * (λ express) = 1 + 2 * (13) = 27이며 올바른 숫자입니다.

+0

+1 "코드 분석이 소스 코드가 아니라 어셈블리에서 IL을보고 있습니다 .Lambda 식을 기본적으로 지원하는 IL은 없습니다" – Lijo

+0

클로저가없는 경우 Lambda/대리자 만 캐시됩니다. 그들을 넘어서. 그렇지 않으면 그렇지 않습니다. 이것이 람다가 비싼 이유 중 하나입니다. JIT, 할당 및 GC도 관련되어 있습니다. 그러나 이것은 다른 논의를위한 것입니다. 내가 생각할 수있는 "뜨거운"방법으로 클로저를 사용하여 lambdas와 관련된 성능 문제를 해결했습니다. –

3

C# 컴파일러는 실제로 람다 (lambdas)를 포함한 익명 메소드에 대해 상당히 "재미있는"일리노이를 생성합니다. 각각에 대해 private 필드를 작성한 다음 소비 메소드에서 해당 값을 지정하기 전에 값이 널 (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). . 지금은 잘못된 양성이라고 생각하면 문제를 무시해야합니다.