2012-04-20 15 views
8

tenemos este código, sortof: análisis¿Cómo puede la complejidad ciclomática ser 27 en un método con 13 suscripciones de controlador de eventos?

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

Código de VS10 último dice "complejidad ciclomática de 27". La eliminación de una de las líneas aumenta la complejidad ciclomática 25.

No hay ramificaciones, ¿cómo es posible?

Respuesta

17

Recuerde que el Análisis de código está mirando el IL en su ensamblaje, no su código fuente. No hay nada en el IL que soporte nativamente expresiones lambda, entonces son una construcción del compilador. Puede encontrar los detalles de la salida here. Pero básicamente tu expresión lambda se convierte en una clase estática privada que es un deligate anónimo. Sin embargo, en lugar de crear una instancia del deligate anónimo cada vez que se hace referencia en el código, el deligate se almacena en caché. Así que cada vez que asigna una expresión lambda, hace una comprobación para ver que se ha creado una instancia de esa lambda deligate, si es así utiliza el deligate en caché. Eso genera un if/else en el IL aumentando la complejidad en 2. Entonces, en esta función, la complejidad es 1 + 2 * (lambda express) = 1 + 2 * (13) = 27, que es el número correcto.

+0

+1 para "Recuerde que el Análisis de código está mirando el IL en su ensamblaje, no su código fuente. No hay nada en el IL que admita originalmente expresiones lambda" – Lijo

+0

Lambdas/delegados SOLO SE CACHEDAN si no hay cierre sobre ellos. De lo contrario, no lo son. Esta es una de las razones (de varias) que las lambdas son costosas. También hay JIT, asignación y GC involucrados, pero eso es para otra discusión. He solucionado más problemas de rendimiento relacionados con lambdas con cierres en métodos "calientes" que puedo contar. –

1

mejor conjetura es que esto se debe probablemente a las declaraciones anteriores de ser convertido al formato de descriptor de acceso de eventos, a saber

class MyClass 
{ 
    private event EventHandler MyPrivateEvent; 

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

Ver http://msdn.microsoft.com/en-us/magazine/cc163533.aspx y http://www.switchonthecode.com/tutorials/csharp-tutorial-event-accessors para las discusiones sobre el formato del evento de acceso.

3

El compilador C# realmente genera algunos IL bastante "interesantes" para métodos anónimos, incluyendo lambdas. Para cada uno, crea un campo privado, luego, antes de asignar su valor en el método de consumo, comprueba si el valor es nulo, lo que agrega una rama If al método compilado. La herramienta de métricas de código debe ignorar esto (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), y podemos esperar que finalmente lo haga . Por ahora, prácticamente tiene que ignorar el problema si cree que es un falso positivo.

Cuestiones relacionadas