c# - ¿Cuáles son las reglas para los argumentos con nombre y por qué?
syntax language-design (6)
Creo que el diseño del lenguaje en este caso se basa en el primer argumento nombrado de cualquier función.
Usando tu ejemplo
void RegisterUser(int age, string firstname, string lastname);
y llamándolo
RegisterUser(25, firstname: "John", lastname: "Smith");
Antes de encontrar el primer argumento, el compilador no sabe si esta función va a utilizar algún argumento con nombre. Por lo tanto, es una suposición segura para el compilador hacer mapeo secuencial.
25:
El compilador obtiene el primer argumento y, si no tiene nombre, se asignará de inmediato con el primer argumento de la definición de la función.
nombre de pila:
Tan pronto como se encuentre con su primer argumento con nombre, las cosas cambiarán, ya que el compilador ahora tendrá que verificar todos los argumentos restantes mencionados en la definición de la función para asignar el argumento con nombre actual.
Después de que se asigna correctamente, el primer argumento con nombre se ha roto el rastro de la asignación secuencial. Y por lo tanto, no es factible proporcionar un argumento sin nombre al compilador ahora, ya que ahora no puede establecer dónde mapearlo.
Si crees que debería recordar el último argumento sin nombre e iniciar el mapeo secuencial desde allí, entonces eso también es propenso a errores, ya que el argumento nombrado que se acaba de definir también podría ser secuencialmente correcto.
apellido:
Y para los argumentos nombrados es una brisa.
Espero que esto ayude :)
Considera un método como este
void RegisterUser(string firstname, string lastname, int age);
Me gusta nombrar explícitamente los argumentos de métodos como este cuando los llamo porque es fácil para alguien mezclar los argumentos de nombre y lastname
. Sin embargo, no es realmente necesario para la age
. Por ejemplo, creo que esto debería estar bien desde un punto de vista de claridad.
RegisterUser(firstname: "John", lastname: "Smith", 25);
Pero se lanzaría el siguiente error:
Las especificaciones de los argumentos con nombre deben aparecer después de que se hayan especificado todos los argumentos fijos
Otra cosa interesante es que si la firma fuera
void RegisterUser(int age, string firstname, string lastname);
luego llamándolo de la siguiente manera NO arroja un error
RegisterUser(25, firstname: "John", lastname: "Smith");
¿Por qué C # está diseñado de esta manera? ¿Existe una complicación para el compilador si se permitiera el primer escenario?
El uso previsto, con:
void M(int a = -1, int b = -1, int c = -1, int d = -1, int e = -1);
como ejemplo, es que puede especificar un subconjunto de esos parámetros opcionales por notación posicional:
M(42, 28, 101); // gives a, b, and c in order; omits d and e
o puedes usar argumentos con nombre:
M(d: 50, a: 42, c: 101); // gives three arguments in arbitrary order
o puede combinarlos, donde comience con argumentos posicionales y luego cambie a nombrar argumentos:
M(42, 28, e: 65537, d: 50); // mixed notation OK
La razón de la restricción que ha encontrado es que cosas como:
M(c: 101, 7, 9, b: 28, 666); // ILLEGAL!
sería confuso
Puedo ver que usted propone mantener el orden posicional en su llamada específica, y luego incluir los nombres de algunos argumentos solamente, para mayor claridad. Sin embargo, parece que este uso no era una prioridad para los diseñadores de idiomas.
Le sugiero que nombre todos los argumentos cuando su razón para usar el estilo con nombre es la claridad (a diferencia de la necesidad de especificar un subconjunto adecuado de los parámetros solamente).
Esto se debe a que cuando nombra argumentos, el compilador los asigna en función de los nombres e ignora la definición de la función siempre que estén presentes todos los argumentos requeridos. En tu caso no sabe lo que es 25. A nosotros nos parece lógico que tenga que ser la edad, pero si cambias tu ejemplo a:
void RegisterUser(string firstname, string lastname, int age = 0, int weight = 0);
y luego diga:
RegisterUser(firstname: "John", lastname: "Smith", 25);
Entonces, el compilador no sabe qué hacer con los últimos 25. Esta forma de llamar a una función se usa principalmente en funciones que tienen muchos valores predeterminados en los que solo desea establecer algunos.
Cuando no nombra sus argumentos, básicamente está diciendo que sigue estrictamente la estructura establecida por la definición de la función.
Los argumentos posicionales se colocan antes de los argumentos nombrados. Los argumentos posicionales siempre se refieren al parámetro correspondiente en la declaración del método .
Supongamos que mi método es:
void Dimensions(int height, int breadth , int length);
y lo estoy llamando como
Dimensions(3, length: 12, 24);
En este caso:
''3'' es el primer parámetro y se refiere a la altura, pero ''24'' es el tercer parámetro y se refiere a la longitud, pero ya hemos especificado el valor de la longitud.
Entonces, tal vez para superar este obstáculo, por defecto el estilo c # es posicionar los argumentos posicionales al comienzo para proporcionar referencias correctas.
Además, si estamos definiendo parámetros opcionales, proporcionar parámetros posicionales al final puede dar lugar a resultados incorrectos.
Todos los argumentos nombrados tienen que venir después de los argumentos posicionales; No puedes cambiar entre los estilos. Los argumentos posicionales siempre se refieren al parámetro correspondiente en la declaración del método. No puede hacer que los argumentos posicionales omitan un parámetro especificándolo más adelante con un argumento con nombre. El compilador utiliza variables locales temporales. Luego, reordena los locales en las ranuras de argumentos, mi conjetura es que el compilador se enlaza por argumentos hasta que encuentra un argumento con nombre y luego descarta los argumentos que ya ha enlazado sin nombres y reordenados, ya que el compilador utiliza variables locales temporales. Enlaza el resto por nombre, por ejemplo, enlaza 25 con la edad y luego el primer nombre: "John", apellido: "Smith"
el compilador podría ser capaz de resolverlo, pero para nosotros, los simples humanos, sería casi imposible saber si 25 se refiere al primer o tercer parámetro. Sobre todo porque abre la posibilidad de mezclar argumentos. Por qué no
MyFunction(firstname: "josh", 25, "smith", someotherargument: 42)
¿Cómo interpretarías esto, 25 para la edad y Smith para el apellido? Haz una regla para ello y un compilador puede implementarlo. Pero lo que tendría sentido para los humanos. La ofuscación de código no debería ser tan fácil
Un lenguaje debe hacer que sea difícil cometer errores, no más fácil
NOTA: las cosas extrañas comienzan a suceder con el pedido si los argumentos anteriores se nombran más adelante. (como el nombre y smith en mi ejemplo) porque entonces se convierte en un rompecabezas para que sus argumentos sin nombre se asignen a los argumentos correctos. Se podría hacer, pero el código no debería producir rompecabezas.