remarks - which example is a valid visual c# xml documentation comment




La declaración de devolución faltante en un método no válido compila (9)

Encontré una situación en la que un método no nulo falta una declaración de devolución y el código aún se compila. Sé que las instrucciones después del ciclo while son inalcanzables (código muerto) y nunca se ejecutarán. ¿Pero por qué el compilador ni siquiera advierte sobre devolver algo? ¿O por qué un idioma nos permitiría tener un método no nulo que tenga un ciclo infinito y no devuelva nada?

public int doNotReturnAnything() {
    while(true) {
        //do something
    }
    //no return statement
}

Si agrego una sentencia break (incluso una condicional) en el ciclo while, el compilador se queja de los errores infames: 'El método no devuelve un valor' (Eclipse) y 'No todas las rutas de códigos devuelven un valor' (Visual Studio)

public int doNotReturnAnything() {
    while(true) {
        if(mustReturn) break;
        //do something
    }
    //no return statement
}

Esto es cierto para Java y C #


¿Por qué un lenguaje nos permite tener un método no nulo que tiene un ciclo infinito y no devuelve nada?

La regla para los métodos no nulos es que cada ruta de código que devuelve debe devolver un valor , y esa regla se cumple en su programa: cero de cero rutas de código que regresan devuelven un valor. La regla no es "cada método no nulo debe tener una ruta de código que retorna".

Esto le permite escribir stub-methods como:

IEnumerator IEnumerable.GetEnumerator() 
{ 
    throw new NotImplementedException(); 
}

Ese es un método no vacío. Tiene que ser un método no nulo para satisfacer la interfaz. Pero parece una tontería hacer que esta implementación sea ilegal porque no devuelve nada.

Que su método tiene un punto final inalcanzable debido a un goto (recuerde, un while(true) es simplemente una forma más agradable de escribir goto ) en lugar de un throw (que es otra forma de goto ) no es relevante.

¿Por qué el compilador ni siquiera advierte sobre devolver algo?

Porque el compilador no tiene buena evidencia de que el código sea incorrecto. Alguien escribió while(true) y parece probable que la persona que hizo eso sabía lo que estaban haciendo.

¿Dónde puedo leer más sobre el análisis de accesibilidad en C #?

Vea mis artículos sobre el tema, aquí:

ATBG: alcanzabilidad de facto y de jure

Y también podría considerar leer la especificación C #.


"¿Por qué el compilador ni siquiera advierte sobre devolver algo? ¿O por qué un lenguaje nos permite tener un método no nulo que tiene un ciclo infinito y no devuelve nada?".

Este código también es válido en todos los demás idiomas (¡probablemente excepto Haskell!). Porque la primera suposición es que estamos "intencionalmente" escribiendo algún código.

Y hay situaciones en las que este código puede ser totalmente válido, como si fuera a usarlo como un hilo; o si devolvía una Task<int> , podría hacer una comprobación de errores basada en el valor int devuelto, que no debería devolverse.


El compilador de Java es lo suficientemente inteligente como para encontrar el código inalcanzable (el código después del ciclo while)

y dado que es inalcanzable , no tiene sentido agregar una declaración de return allí (después de los extremos)

lo mismo ocurre con el condicional if

public int get() {
   if(someBoolean) {   
     return 10;
   }
   else {
     return 5;
   }
   // there is no need of say, return 11 here;
}

dado que la condición booleana someBoolean solo puede evaluar como true o false , no es necesario proporcionar una return explícitamente después de if-else , porque ese código es inalcanzable y Java no se queja de ello.


El compilador es lo suficientemente inteligente como para descubrir que tu ciclo while es infinito.

Entonces el compilador no puede pensar por ti. No puede adivinar por qué escribió ese código. Lo mismo representa los valores de retorno de los métodos. Java no se quejará si no hace nada con los valores de retorno del método.

Por lo tanto, para responder a su pregunta:

El compilador analiza su código y después de descubrir que ninguna ruta de ejecución conduce a caerse al final de la función, termina con OK.

Puede haber razones legítimas para un ciclo infinito. Por ejemplo, muchas aplicaciones usan un bucle principal infinito. Otro ejemplo es un servidor web que puede esperar indefinidamente las solicitudes.


En la teoría de tipos, hay algo llamado el tipo de fondo que es una subclase de cualquier otro tipo (!) Y se utiliza para indicar la no terminación entre otras cosas. (Las excepciones pueden contar como un tipo de no terminación: no finaliza a través de la ruta normal).

Entonces, desde una perspectiva teórica, se puede considerar que estas declaraciones que no terminan devuelven algo de tipo Bottom, que es un subtipo de int, de modo que uno obtiene (tipo de) su valor de retorno después de todo desde una perspectiva de tipo. Y está perfectamente bien que no tenga ningún sentido que un tipo pueda ser una subclase de todo lo demás, incluso int, porque en realidad nunca devuelve uno.

En cualquier caso, a través de la teoría explícita de tipos o no, los compiladores (escritores de compiladores) reconocen que pedir un valor de retorno después de una declaración no terminada es tonto: no hay ningún caso posible en el que pueda necesitar ese valor. (Puede ser agradable que su compilador lo advierta cuando sabe que algo no terminará pero parece que quiere que devuelva algo. Pero es mejor dejarlo para los inspectores de estilo a la pelusa, ya que tal vez necesite la firma de tipo que forma por alguna otra razón (por ejemplo, subclases) pero realmente quiere la no terminación.)


La especificación de Java define un concepto llamado Unreachable statements . No tiene permitido tener una declaración inalcanzable en su código (es un error de tiempo de compilación). Ni siquiera está permitido tener una declaración de devolución después del tiempo (verdadero); declaración en Java. Un while(true); La declaración hace que las siguientes declaraciones sean inalcanzables por definición, por lo tanto, no necesita una declaración de return .

Tenga en cuenta que si bien el problema de Detener es indecidible en un caso genérico, la definición de Declaración inalcanzable es más estricta que simplemente detenerse. Está decidiendo casos muy específicos donde un programa definitivamente no se detiene. El compilador teóricamente no puede detectar todos los bucles infinitos y las sentencias inalcanzables, pero tiene que detectar casos específicos definidos en la especificación (por ejemplo, el caso while(true) )


No hay ninguna situación en la que la función pueda alcanzar su fin sin devolver un valor apropiado. Por lo tanto, el compilador no tiene nada de qué quejarse.


Puedo estar equivocado, pero algunos depuradores permiten la modificación de variables. Aquí, mientras que x no es modificado por código y será optimizado por JIT uno podría modificar x a falso y el método debería devolver algo (si tal cosa está permitida por C # depurador).


Visual Studio tiene el motor inteligente para detectar si ha escrito un tipo de devolución y luego debe tener una declaración de devolución en la función / método.

Al igual que en PHP, su tipo de devolución es verdadero si no ha devuelto nada. el compilador obtiene 1 si nada ha regresado.

A partir de este

public int doNotReturnAnything() {
    while(true) {
        //do something
    }
    //no return statement
}

El compilador sabe que, si bien la declaración en sí misma tiene una naturaleza poco clara, no la considere. y el compilador php se volverá verdadero automáticamente si escribe una condición en la expresión de while.

Pero no en el caso de VS le devolverá un error en la pila.





design