variable una referencia que por pasar parametros parametro objeto name metodo entrada acceder c# override params virtual-method params-keyword

c# - una - Cambiar el modificador de params en un método de anulación



pasar un objeto a un metodo en c# (2)

Creo que se describe en el párrafo 1.6.6.4 de la especificación de c #:

Un método virtual se puede anular en una clase derivada. Cuando una declaración de método de instancia incluye un modificador de anulación, el método anula un método virtual heredado con la misma firma. Mientras que una declaración de método virtual introduce un nuevo método, una declaración de método de anulación especializa un método virtual heredado existente al proporcionar una nueva implementación de ese método.

De acuerdo con esto, virtual declaración del método virtual es realmente importante aquí. Y la declaración del método virtual se utiliza en cada llamada a ese método. Las implementaciones de override n correctas (si se especifican) se toman en tiempo de ejecución, donde params no tiene nada que hacer en absoluto.

Se puede confirmar por simple prueba:

class Giraffid { public virtual void Eat(params int[] leaves) { Console.WriteLine("G"); } } class Okapi : Giraffid { public override void Eat(int[] leaves) { Console.WriteLine("O"); } }

Con esa declaracion

var o = new Okapi(); o.Eat(1, 2, 3);

Funciona bien al 100%.

Soy consciente de que un modificador de params (que convierte un parámetro del tipo de matriz en una denominada "matriz de parámetros") no forma parte específica de la firma del método. Ahora considera este ejemplo:

class Giraffid { public virtual void Eat(int[] leaves) { Console.WriteLine("G"); } } class Okapi : Giraffid { public override void Eat(params int[] leaves) { Console.WriteLine("O"); } }

Esto se compila sin advertencias. Entonces diciendo:

var okapi = new Okapi(); okapi.Eat(2, 4, 6); // will not compile!

da un error ( No overload for method ''Eat'' takes 3 arguments ).

Ahora, sé que el compilador traduce el modificador de params a una aplicación de System.ParamArrayAttribute en el parámetro en cuestión. En general, no hay problema en aplicar una colección de atributos a un parámetro de un método virtual, y luego decorar el parámetro "correspondiente" en un método de reemplazo en una clase derivada con un conjunto diferente de atributos.

Sin embargo, el compilador elige ignorar mi palabra clave params silenciosamente. Por el contrario, si uno lo hace al revés, y aplica parámetros al parámetro en la clase base Giraffid , y luego omite la palabra clave en la anulación en Okapi , el compilador elige decorar ambos métodos con System.ParamArrayAttribute . Verifiqué estas cosas con IL DASM, por supuesto.

Mi pregunta:

¿Está documentado este comportamiento? He buscado exhaustivamente en la Especificación de lenguaje C # sin encontrar ninguna mención de esto.

Puedo decir que al menos el entorno de desarrollo de Visual Studio está confundido acerca de esto. Al escribir 2, 4, 6 en la llamada al método anterior, el intellisense me muestra el void Okapi.Eat(params int[] leaves) en una sugerencia .

Para la comparación, también intenté implementar un método de interfaz y cambiar la presencia / ausencia de params en la interfaz y la clase de implementación, e intenté definir un tipo de delegado y cambiar los params o no en la definición del tipo de delegado o en el método cuyo grupo de métodos asigné a una variable de mi tipo delegado. En estos casos era perfectamente posible cambiar el estado de los params .


El comportamiento del compilador es correcto, pero esto es un poco desordenado. Hubiera preferido que esto fuera al menos una advertencia.

No es sorprendente que no pueda encontrar en la especificación que dice que esto es correcto. Los bits relevantes son:

El procesamiento en tiempo de encuadernación de una invocación del método de la forma M (A), donde M es un grupo de métodos, y A es una lista de argumentos opcional, consta de los siguientes pasos: Se construye el conjunto de métodos candidatos para la invocación del método. . Para cada método F asociado con el grupo de métodos M, si F no es genérico, F es un candidato cuando M no tiene una lista de argumentos de tipo, y F es aplicable con respecto a A.

¿Cuáles son los "métodos asociados con el grupo de métodos M"? Bueno, primero que nada, ¿qué es un grupo de métodos?

Un grupo de métodos, que es un conjunto de métodos sobrecargados que resultan de una búsqueda de miembros ...

OK, entonces, ¿cuáles son las reglas de búsqueda de miembros?

De lo contrario, el conjunto consta de todos los miembros accesibles denominados N en T, incluidos los miembros heredados y los miembros accesibles denominados N en objeto. Los miembros que incluyen un modificador de anulación se excluyen del conjunto.

Énfasis añadido.

El resultado práctico aquí es que, a los fines de la resolución de sobrecarga, se considera que un método anulado es el método que se declaró originalmente , no el método que anuló . Esta regla es, por desgracia, violada en este caso:

virtual void M(int x, int y) { } ... override void M(int y, int x) { } ... M(x = 1, y = 2);

La resolución de sobrecarga utiliza los nombres de la versión más derivada . Esta es una consecuencia desafortunada del hecho de que los argumentos con nombre se agregaron muy tarde en el juego.

En resumen: para los fines de determinar si un método es "params" o no, el análisis se realiza en el método original , no en el método de anulación .

Hubiera sido bueno si el compilador le hubiera dado una advertencia aquí.

Se puede decir que al menos el entorno de desarrollo de Visual Studio está confundido acerca de esto.

Correcto. La capa IntelliSense siempre muestra la información del método para el método de anulación, no el método anulado. La investigación mostró que a los usuarios les resultó confuso cuando se crearon los métodos para que parecieran el método de declaración original, no el método de anulación. Y, por supuesto, como mencioné anteriormente, esos son los nombres de los parámetros que usaremos para los argumentos con nombre.