8

abbiamo questo codice, sortof: analisiCome può la complessità ciclomatica essere 27 in un metodo con 13 sottoscrizioni di gestori di eventi?

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

Codice in VS10 finale dice: "la complessità ciclomatica di 27". Rimozione di una delle linee rende la complessità ciclomatica 25.

Non ci sono ramificazioni in corso, quindi come è possibile?

risposta

17

Ricordare che l'analisi del codice esamina l'IL nel proprio assieme, non il codice sorgente. Non c'è nulla nell'IL che supporti in modo nativo le espressioni lambda, quindi sono un costrutto del compilatore. È possibile trovare le specifiche di ciò che è here ouput. Ma fondamentalmente la tua espressione lambda è trasformata in una classe statica privata che è un deligato anonimo. Tuttavia, piuttosto che creare un'istanza del delegato anonimo ogni volta che viene fatto riferimento nel codice, il deligate viene memorizzato nella cache. Pertanto, ogni volta che assegni un'espressione lambda, verifica se è stata creata un'istanza di quel delda lambda, in tal caso utilizza il deligato memorizzato nella cache. Questo genera un if/else nell'IL aumentando la complessità di 2. Quindi in questa funzione la complessità è 1 + 2 * (lambda express) = 1 + 2 * (13) = 27 che è il numero corretto.

+0

+1 per "Ricordare che l'analisi del codice sta esaminando l'IL nel proprio assieme, non il codice sorgente. Non c'è nulla nell'IL che supporti nativamente le espressioni lambda" – Lijo

+0

Lambdas/delegati sono SOLO CACCATI SE non c'è chiusura sopra di loro. Altrimenti, non lo sono. Questo è uno dei motivi (di più) lambda sono costosi. Ci sono anche JIT, allocazione e GC coinvolti - ma questo è per un'altra discussione. Ho risolto più problemi di prestazioni relativi a lambda con chiusure in metodi "caldi" che posso contare. –

1

ipotesi migliore è che questo è probabilmente dovuto alle dichiarazioni di cui sopra viene convertito nel formato di accesso all'evento, cioè

class MyClass 
{ 
    private event EventHandler MyPrivateEvent; 

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

Vedere http://msdn.microsoft.com/en-us/magazine/cc163533.aspx e http://www.switchonthecode.com/tutorials/csharp-tutorial-event-accessors per le discussioni sul formato dell'evento di accesso.

3

Il compilatore C# genera in realtà un IL abbastanza "interessante" per metodi anonimi, incluso lambdas. Per ognuno, crea un campo privato quindi, prima di assegnare il suo valore nel metodo di consumo, controlla se il valore è nullo, che aggiunge un ramo If al metodo compilato. Lo strumento di metrica del codice dovrebbe ignorare questo (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) e possiamo sperare che alla fine . Per ora, devi quasi ignorare il problema se ritieni che sia un falso positivo.

Problemi correlati