sharp parametros parametro parameter opcionales opcional metodos method funciones c# overloading ambiguity optional-arguments

c# - parametros - parametro opcional c sharp



¿Por qué C#permite llamadas de función ambiguas a través de argumentos opcionales? (3)

Su punto de que Eric Lippert podría tener una respuesta me llevó a este https://meta.stackoverflow.com/a/323382/1880663 , lo que hace que suene como si mi pregunta solo lo molestara. Trataré de reformularlo para aclarar que estoy preguntando sobre el diseño del idioma y que no estoy buscando una referencia específica.

¡Lo aprecio! Estoy feliz de hablar sobre el diseño del lenguaje; Lo que me molesta es cuando pierdo el tiempo haciendo eso cuando el interrogador no está claro qué es lo que realmente satisfaría su solicitud. Creo que tu pregunta fue formulada claramente.

El comentario a tu pregunta publicado por Hans es correcto. El equipo de diseño de idiomas estaba al tanto del problema que plantea, y esto está lejos de ser la única ambigüedad potencial creada por los argumentos opcionales / nombrados. Durante mucho tiempo, consideramos muchos escenarios y diseñamos la función con el mayor cuidado posible para mitigar posibles problemas.

Todos los procesos de diseño son el resultado de un compromiso entre los principios de diseño en competencia. Obviamente, había muchos argumentos para la característica que debía equilibrarse con los costos significativos de diseño, implementación y prueba, así como los costos para los usuarios en forma de confusión, errores, etc., de la construcción accidental de ambigüedades como la uno que señale

No voy a repetir lo que fueron docenas de horas de debate; Déjame darte los puntos altos.

El escenario de motivación principal para la característica fue, como señala Hans, la demanda popular, particularmente proveniente de desarrolladores que usan C # con Office. (Y la revelación completa, como un miembro del equipo que escribió el modelo de programación en C # para Word y Excel antes de unirme al equipo en C #, fui literalmente el primero en solicitarlo; la ironía de que luego tuve que implementar esta característica difícil a Un par de años más tarde no me perdí. Los modelos de objetos de Office se diseñaron para ser utilizados desde Visual Basic, un lenguaje que desde hace mucho tiempo tiene soporte de parámetros opcional / nombrado.

C # 4 podría haber parecido una versión un poco "delgada" en términos de características obvias. Esto se debe a que gran parte del trabajo realizado en esa versión fue la infraestructura para permitir una interoperabilidad más fluida con modelos de objetos diseñados para lenguajes dinámicos. La función de escritura dinámica es la más obvia, pero se agregaron muchas otras funciones pequeñas que se combinan para facilitar el trabajo con modelos de objetos COM dinámicos y heredados. Argumentos nombrados / opcionales fue solo uno de ellos.

El hecho de que tuviéramos idiomas existentes como VB que tenían esta característica específica durante décadas y el mundo aún no había terminado, era una prueba más de que la característica era tanto factible como valiosa. Es genial tener un ejemplo donde puede aprender de sus éxitos y fracasos antes de diseñar una nueva versión de la característica.

En cuanto a la situación específica que mencionas: consideramos hacer cosas como detectar cuándo había una posible ambigüedad y hacer una advertencia, pero eso abre otras latas de gusanos. Las advertencias deben ser para el código que es común, verosímil y, casi con seguridad, incorrecto, y debe haber una manera clara de solucionar el problema que hace que la advertencia desaparezca. Escribir un detector de ambigüedad es mucho trabajo; Créanme, se tardó más en escribir la detección de ambigüedad en la resolución de sobrecarga que en escribir el código para manejar casos exitosos. No quisimos dedicar mucho tiempo a agregar una advertencia para un escenario raro que es difícil de detectar y que no haya un consejo claro sobre cómo eliminar la advertencia.

Además, francamente, si escribe un código en el que tiene dos métodos con el mismo nombre que hacen algo completamente diferente dependiendo de cuál llame, ¡ya tiene un problema de diseño mayor en sus manos! Solucione ese problema primero, en lugar de preocuparse de que alguien llame accidentalmente al método incorrecto; haz que cualquiera de los dos métodos sea el correcto para llamar.

Encontré esto hoy, y me sorprende que no lo haya notado antes. Dado un simple programa de C # similar al siguiente:

public class Program { public static void Main(string[] args) { Method(); // Called the method with no arguments. Method("a string"); // Called the method with a string. Console.ReadLine(); } public static void Method() { Console.WriteLine("Called the method with no arguments."); } public static void Method(string aString = "a string") { Console.WriteLine("Called the method with a string."); } }

Obtendrá el resultado que se muestra en los comentarios para cada llamada de método.

Entiendo por qué el compilador elige las sobrecargas que hace, pero ¿por qué se permite esto en primer lugar? No pregunto cuáles son las reglas de resolución de sobrecargas, las comprendo, pero sí pregunto si hay una razón técnica por la que el compilador permite ¿qué son esencialmente dos sobrecargas con la misma firma?

Por lo que puedo decir, una función de sobrecarga con una firma que difiere de otra sobrecarga solo a través de tener un argumento opcional adicional no ofrece nada más que lo haría si el argumento (y todos los argumentos anteriores) fueran simplemente requeridos.

Una cosa que sí hace es hacer posible que un programador (que probablemente no esté prestando suficiente atención) piense que está llamando a una sobrecarga diferente a la que realmente es.

Supongo que es un caso bastante infrecuente, y la respuesta de por qué se permite esto puede ser simplemente porque no vale la pena la complejidad para rechazarlo, pero hay otra razón por la que C # permite que las sobrecargas de funciones se diferencien de las demás solo por tener un opcional adicional. ¿argumento?


Creo que esta pregunta básicamente se reduce a cómo esas firmas están representadas por el lenguaje intermedio. Tenga en cuenta que las firmas de ambas sobrecargas no son iguales ! El segundo método tiene una firma como esta:

.method public hidebysig static void Method([opt] string aString) cil managed { .param [1] = string(''a string'') // ... }

En IL la firma del método es diferente. Toma una cadena, que está marcada como opcional. Esto cambia el comportamiento de cómo se inicializa el parámetro, pero no cambia la presencia de este parámetro.

El compilador no puede decidir qué método está llamando, por lo que utiliza el que mejor se adapta a los parámetros que proporcione. Como no proporcionó ningún parámetro para la primera llamada, se supone que está llamando a la sobrecarga sin ningún parámetro.

Al final es una pregunta sobre el buen diseño de código. Como regla general, o uso parámetros opcionales o sobrecargas, dependiendo de lo que quiera hacer: los parámetros opcionales son buenos, si la lógica dentro del método no depende de los argumentos proporcionados, mientras que las sobrecargas son buenas para proporcionar una implementación diferente para diferentes conjuntos de argumentos. Si alguna vez comprueba si un parámetro es igual a un valor predeterminado para decidir qué hacer, es probable que deba realizar una sobrecarga. Por otro lado, si te encuentras repitiendo grandes trozos de código en muchas sobrecargas, deberías intentar extraer parámetros opcionales.

También hay una buena respuesta de Chuck Skeet a esta pregunta .


Este comportamiento es especificado por Microsoft en el MSDN. Eche un vistazo a Argumentos con nombre y opcionales (Guía de programación de C #) .

Si dos candidatos se consideran igualmente buenos, la preferencia es para un candidato que no tiene parámetros opcionales para los cuales se omitieron los argumentos en la convocatoria. Esto es consecuencia de una preferencia general en la resolución de sobrecarga para los candidatos que tienen menos parámetros.

Una razón por la que decidieron implementarlo de esta manera podría ser si desea sobrecargar un método después. Así que no tienes que cambiar todas tus llamadas de método que ya están escritas.

ACTUALIZAR

Estoy sorprendido, también Jon Skeet no tiene una explicación real de por qué lo hicieron así.