¿Por qué C# no me permite llamar a un método void como parte de la declaración return?


Tengo curiosidad si hay una razón legítima de por qué C# no admite llamar a un método void como parte de la instrucción return cuando el tipo de retorno del método que llama también es void.

public void MethodA() 
{ 
    return; 
}

public void MethodB() 
{
    return MethodA();
}

Así que normalmente veríamos esto:

public void MethodMeh() 
{
    if (expression) 
    {
        MethodA();
        return;
    }

    // Do more stuff
}

... cuando podríamos estar usando esto en su lugar:

public void MethodAwesome() 
{
    if (expression) 
        return MethodA();

    // Do more stuff
}

¿Es esta una limitación del lenguaje debido a cómo C# maneja void?

 37
Author: Matt Beckman, 2014-07-10

9 answers

Porque es simplemente la forma en que se define el lenguaje.

Un método puede usar instrucciones return para devolver control a su llamador. En un método que devuelve void, return las declaraciones no pueden especificar un expresion. En un método que devuelve non-void, return las declaraciones deben incluya una expresión que calcule el valor devuelto.

Es una decisión arbitraria (presumiblemente hecha para la compatibilidad con ANSI C y sus otros descendientes), y otros los idiomas hacen las cosas de manera diferente.

Por ejemplo, en Python, todas las funciones devuelven un valor. Si ejecuta una instrucción return sin un valor, o deja que control llegue al final de la función, entonces es como si hubiera escrito return None.

Por el contrario, Pascal limita la terminología de function a subprogramas que tienen un valor de retorno; si no desea devolver nada, use un procedure en su lugar.

 39
Author: dan04,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-10 00:40:23

void es la ausencia de información; no tiene ningún sentido volver. No es un tipo*, y no es un valor, a diferencia de otros idiomas. No, eso no es realmente una limitación.

* bueno, algo Así, como @Lucas señala. Es un tipo informativo; en realidad no representa un tipo en el sentido habitual. No puedes tener uno.

 28
Author: Ry-,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-24 16:24:29

Su pregunta es más o menos sobre la diferencia entre el tipo void y el tipo unit (más comúnmente visto en lenguajes funcionales como F#).

Básicamente, void no es un tipo real. Mientras que hay System.Void para fines de reflexión, no se puede usar void en la mayoría de los lugares donde se puede usar un tipo real: no se puede tener una variable de tipo void y no se puede usar en genéricos (aunque ser capaz de escribir Func<void> a veces sería muy utilidad).

Por otro lado, unit en F# es un tipo real: tiene un valor (único) (llamado ()), puede escribir el equivalente de Func<void> (escrito unit -> unit, donde el primer unit significa "sin parámetros", similar a escribir void en la lista de parámetros en C) y puede tener variables de tipo unit. Por ejemplo:

let unitTest (f : unit -> unit) =
    let nothing : unit = f()
    ()

La última línea realmente muestra que en F#, a veces tiene que devolver explícitamente unit.

 7
Author: svick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-10 09:14:22

Esto no está permitido de acuerdo con la especificación del idioma. De 15.9.4 de ECMA-334 (énfasis mío):

Una sentencia return con una expresión solo se puede usar en un miembro de función que calcula un valor, que es, un método con un tipo de retorno no nulo , el accessor get de una propiedad o indexador, o un operador.

 4
Author: AlexD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-10 00:26:31

Todo se reduce a las opciones del diseñador del lenguaje.

Desde una perspectiva de tipo, void no tiene valores enumerables, por lo que no tiene sentido devolver un valor de tipo "void"? vacío es ausencia de tipo o contexto de evaluación.

No puede crear instancias ni devolver "void" en C# o Java.

Si pudieras hacerlo, entonces también deberías ser capaz de decir:

 void i;
 i = (what would go here?)
 return i;

Lo anterior no tiene ningún sentido, pero es equivalente a lo que usted propone.

Al final, proponiendo que could propagate void return context with the return statement es simplemente una cuestión de azúcar sintáctica, que se reduce a las elecciones hechas por el diseñador del lenguaje.

La especificación del lenguaje C # http://msdn.microsoft.com/en-us/library/aa691305 (v=vs.71). aspx (sección 7.1) dice:

Nada. Esto ocurre cuando la expresión es una invocación de un método con un tipo de retorno de void. Una expresión clasificada como nada solo es válida en el contexto de un declaración-expresión (Sección 8.6).

Por otro lado, el diseñador de C++ realmente eligió permitir solo la construcción que propone, pero fue específicamente para la uniformidad sintáctica en las plantillas. En C++, el tipo de retorno de una función de plantilla puede ser un parámetro de plantilla. (Stroustrop C++ Programming Language p 148) Sin él, habría casos comunes que se compilarían para todos los tipos, pero no para void, como las llamadas a funciones anidadas de tipo T. Para eso razón, lo siguiente es válido C++:

void B() {
  return;
}

void A() {
  return B(); // legal C++ - doesn't yield a value
}

// But even in C++ the next line is illegal
int i = A();

Así que la expresión de sentencia "return B();" donde B es una función void es solo un atajo para "B(); return;" y en realidad no produce un valor, porque no hay tal cosa como un valor void.

 4
Author: codenheim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-10 21:37:03

Tengo una conjetura sobre una razón legítima para esto.

Cuando el compilador ve una expresión, intenta emparejarla con algo de una lista de expresiones conocidas. Se podría decir que hay dos tipos de declaraciones que comienzan con return:

  1. return expr donde expr es una expresión asignable al tipo de retorno declarado del método contenedor
  2. return sin nada más

Estas son declaraciones completamente diferentes, incluso si se ven similar. Pero uno puede compilar al otro, en ciertos casos (al igual que foreach compila a un while más cosas). Por lo tanto, podría agregar una regla que dice que return expr compila a lo que expr; return; compila, siempre que expr se determine que no es de tipo de retorno (es decir, void).

Pero entonces, los implementadores de los compiladores de C# tendrían que permitir que todas las expresiones no tengan tipo de retorno, cuando normalmente solo se permite que las sentencias no tengan tipo de retorno. Si hicieron esto, entonces tendrían que rechazar manualmente expresiones de ningún tipo donde se requiera un tipo real. Por ejemplo, en las expresiones que actúan como argumentos para una llamada a una función MyMethod(1, 2, SomethingVoid()), el compilador tendría que comprobar adicionalmente si alguna de estas expresiones no devuelve un tipo. Y para cada nuevo tipo de expresión añadida a C# en el futuro, se tendría que añadir la misma comprobación.

Lo anterior es posible, pero sucedería por ninguna otra razón que no sea permitir la no declaración las expresiones en el árbol de sintaxis abstracta (que se genera durante la compilación) no tienen tipo de retorno, y ese sería el caso solo para permitir una estructura sintáctica menor, y una que tiene una alternativa que ya no es (al pulsar teclas) para escribir y posiblemente más clara para leer.

Al final, no parece que valga la pena.

 2
Author: Theodoros Chatzigiannakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-10 11:30:05

El título de la pregunta real no parece estar cubierto por las respuestas, aunque pueden estar llegando a lo correcto. You're question title

¿Por qué C# no admite devolver un método con un tipo de retorno nulo

En realidad C# permite esto, solo que no en el formato que estás intentando. Usar la palabra clave void como otros han respondido significa que el método no devuelve nada. Si desea devolver un método que no devuelve nada, entonces usted quiere hacer algo así:

public Action MethodExample()
{
    return () => { Console.WriteLine("Hello World!"); };
}

Entonces una simple llamada te dará esta acción:

var action = MethodExample();
action(); // prints Hello World
 2
Author: Ian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-10 14:14:44

A void está vacío. La palabra clave void en el lenguaje C# indica que un el método no devuelve nada. Cuando se invoca un método void, no tiene resultado y no se puede asignar ninguna variable.

Ver esta explicación

 1
Author: bumbumpaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-10 00:27:42

Corrígeme si estoy equivocado pero creo que es porque:

public void MethodA() 
{ 
    return; 
}

public void MethodB() 
{
    return MethodA();
}

Sería lo mismo que(que son legales):

public void MethodA() 
{ 

}

public void MethodB() 
{
    MethodA();
}

Y también:

public void MethodMeh() 
{
    if (expression) 
    {
        MethodA();
    }else{
    // do more stuff
    }
}
 -1
Author: b1ub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-10 16:28:17