support - ¿Por qué C#no me permite llamar a un método nulo como parte de la declaración de devolución?
telefono web (9)
Tengo curiosidad por saber por qué C # no es compatible con llamar a un método nulo como parte de la declaración de devolución cuando el tipo de devolución del método de llamada también es nulo.
public void MethodA()
{
return;
}
public void MethodB()
{
return MethodA();
}
Entonces 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 esto una limitación de idioma debido a cómo C # maneja nulo?
Un vacío está vacío. La palabra clave void en el lenguaje C # indica que un método no devuelve nada. Cuando se invoca un método vacío, no tiene ningún resultado y no se puede asignar ninguna variable.
Adivino una razón legítima para esto.
Cuando el compilador ve una expresión, intenta hacerla coincidir con algo de una lista de expresiones conocidas. Se podría decir que hay dos tipos de declaraciones que comienzan con el return
:
-
return expr
dondeexpr
es una expresión asignable al tipo de devolución declarada del método contenedor -
return
sin otra cosa
Estas son declaraciones completamente diferentes, incluso si parecen similares. Pero uno puede compilar para el otro, en ciertos casos (al igual que las compilaciones foreach
por un while
más cosas). Entonces, podría agregar una regla que diga que return expr
compila a cualquier expr; return;
expr; return;
compila a, siempre que se determine que expr
es de tipo devuelto (es decir, void
).
Pero entonces, los implementadores de los compiladores de C # tendrían que permitir que todas las expresiones no tengan ningún tipo de retorno, cuando normalmente solo las declaraciones tienen permiso para no tener tipo de retorno. Si lo hicieran, tendrían que rechazar manualmente las expresiones de ningún tipo donde se requiera un tipo real. Por ejemplo, en las expresiones que actúan como argumentos para una función, MyMethod(1, 2, SomethingVoid())
, el compilador también deberá verificar si alguna de estas expresiones no devuelve un tipo. Y por cada nuevo tipo de expresión añadida a C # en el futuro, se debería agregar el mismo cheque.
Lo anterior es posible, pero ocurriría sin otra razón que permitir que las expresiones no declarativas en el árbol de sintaxis abstracta (que se genera durante la compilación) no tengan tipo de retorno, y ese sería el caso solo para permitir una sintaxis menor estructura - y una que tiene una alternativa que ya no está (en teclas) para escribir y posiblemente más clara para leer.
Al final, no parece que valga la pena.
Corrígeme si estoy equivocado, pero creo que es porque:
public void MethodA()
{
return;
}
public void MethodB()
{
return MethodA();
}
sería el mismo como (que son legales):
public void MethodA()
{
}
public void MethodB()
{
MethodA();
}
Y también:
public void MethodMeh()
{
if (expression)
{
MethodA();
}else{
// do more stuff
}
}
Esto no está permitido según la especificación del idioma. De 15.9.4 de ECMA-334 (énfasis mío):
Una declaración de retorno con una expresión solo se puede usar en un miembro de función que calcule un valor, es decir, un método con un tipo de devolución no nulo , el acceso de obtención de una propiedad o indizador, o un operador definido por el usuario.
Porque es simplemente la forma en que se define el idioma .
Un método puede usar declaraciones de devolución para devolver el control a su llamador. En un método que devuelve
void
, las declaraciones dereturn
no pueden especificar una expresión. En un método que devuelve novoid
, las declaraciones dereturn
deben incluir 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 lenguajes hacen las cosas de manera diferente.
Por ejemplo, en Python, todas las funciones devuelven un valor. Si ejecuta una declaración de return
sin un valor, o deja que el control llegue al final de la función, entonces es como si hubiera escrito return None
.
En contraste, Pascal limita la terminología de la function
a subprogramas que tienen un valor de retorno; si no quiere devolver nada, utiliza un procedure
lugar.
Su pregunta es más o menos acerca de la diferencia entre el tipo de void
y el tipo de unit
(más comúnmente visto en lenguajes funcionales como F #).
Básicamente, el void
no es un tipo real. Si bien hay System.Void
para propósitos de reflexión, no puedes usar el void
en la mayoría de los lugares donde puedes usar un tipo real: no puedes tener una variable de tipo void
y no puedes usarla en genéricos (aunque capaz de escribir Func<void>
a veces sería muy útil).
Por otro lado, la unit
en F # es un tipo real: tiene un (único) valor (llamado ()
), puede escribir el equivalente a Func<void>
( unit -> unit
escrita unit -> unit
, donde la primera unit
significa "no" parameters ", similar a write 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 muestra que en F #, a veces tiene que devolver la unit
explícitamente.
Su título de pregunta real no parece estar cubierto por las respuestas, aunque pueden estar llegando a lo correcto. Tu eres el título de pregunta
¿Por qué C # no es compatible con devolver un método con un tipo de retorno nulo?
En realidad, C # lo permite, pero 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 desea hacer algo como esto:
public Action MethodExample()
{
return () => { Console.WriteLine("Hello World!"); };
}
Entonces, una simple llamada te dará esta acción:
var action = MethodExample();
action(); // prints Hello World
Todo se reduce a las elecciones del diseñador del lenguaje.
Desde una perspectiva de tipo, el vacío no tiene valores enumerables, por lo que no tiene sentido devolver un valor de tipo "vacío". el vacío es ausencia de tipo o contexto de evaluación.
No puede crear instancias o devolver "vacío" en C # o Java.
Si pudieras hacerlo, entonces también deberías poder decir:
void i;
i = (what would go here?)
return i;
Lo anterior no tiene ningún sentido, pero es equivalente a lo que propones.
Al final, proponer que podamos propagar el contexto de retorno nulo con la declaración de devolución 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 vacío. Una expresión clasificada como nada solo es válida en el contexto de una expresión de declaración (Sección 8.6).
Por otro lado, el diseñador de C ++ realmente optó por permitir solo la construcción que usted propone, pero fue específicamente para la uniformidad sintáctica en las plantillas. En C ++, el tipo de devolución de una función de plantilla puede ser un parámetro de plantilla. (Lenguaje de programación Stroustrop C ++ p 148) Sin él, habría casos comunes que se compilarían para todos los tipos, pero no para nulos, como llamadas de función anidadas de tipo T. Por esa razón, el siguiente es C ++ válido:
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();
Entonces la expresión de declaración "return B ();" donde B es una función vacía es solo un atajo para "B (); return;" y en realidad no produce un valor , porque no existe un valor nulo.
void
es la ausencia de información; no tiene sentido devolverlo. No es un tipo *, y no es un valor, a diferencia de otros idiomas. No, eso no es realmente una limitación.
* Bueno, más o menos, como señala @Lucas. Es un tipo informativo; en realidad, no representa un tipo en el sentido habitual. No puedes tener uno.