Métodos generics y sobrecarga de métodos

La sobrecarga de métodos nos permite definir muchos métodos con el mismo nombre pero con un conjunto diferente de parámetros (por lo tanto, con el mismo nombre pero con una firma diferente).

¿Están estos dos métodos sobrecargados?

class A { public static void MyMethod(T myVal) { } public static void MyMethod(int myVal) { } } 

EDITAR:

No debería el enunciado A.MyMethod(myInt); arrojar un error, dado que el tipo construido A tiene dos métodos con el mismo nombre y la misma firma.

¿Los dos métodos están sobrecargados?

Sí.

No debería el enunciado A.MyMethod(myInt); arrojar un error, dado que el tipo construido A tiene dos métodos con la misma firma?

La pregunta no tiene sentido; A no es un tipo genérico como lo ha declarado. Quizás quisiste preguntar:

Debería la statement A.MyMethod(myInt); hacer que el comstackdor informe un error, ya que hay dos métodos candidatos ambiguos

No. Como otros han dicho, la resolución de sobrecarga prefiere la versión no genérica en este caso. Vea abajo para más detalles.

O quizás quisiste preguntar:

¿Debería la statement de tipo A ser ilegal en primer lugar, ya que en cierto sentido tiene dos métodos con la misma firma, MyMethod y MyMethod ?

No. El tipo A es perfectamente legal. La aridad genérica es parte de la firma . Entonces, no hay dos métodos con la misma firma porque el primero tiene arity genérico cero, el segundo tiene arity genérico uno.

O quizás quisiste preguntar:

 class G { public static void M(T t) {} public static void M(int t) {} } 

El tipo genérico G se puede construir de modo que tenga dos métodos con la misma firma. ¿Es legal declarar tal tipo?

Sí, es legal declarar tal tipo. Por lo general, es una mala idea , pero es legal.

A continuación, puede replicar:

Pero mi copia de la especificación C # 2.0 publicada por Addison-Wesley declara en la página 479 ” Dos miembros de funciones declarados con los mismos nombres … deben tener tipos de parámetros tales que ningún tipo cerrado construido podría tener dos miembros con el mismo nombre y firma. “¿Qué pasa con eso?

Cuando C # 2.0 se diseñó originalmente, ese era el plan. Sin embargo, luego los diseñadores se dieron cuenta de que este patrón deseable sería ilegal:

 class C { public C(T t) { ... } // Create a C from a given T public C(Stream s) { ... } // Deserialize a C from disk } 

Y ahora decimos amigo lo siento, porque se podría decir C , provocando que dos constructores se unifiquen, toda la clase es ilegal. Eso sería desafortunado. Obviamente, es poco probable que alguien construya esto con Stream como parámetro de tipo.

Lamentablemente, la especificación se imprimió antes de que el texto se actualizara a la versión final. La regla en la página 479 no es lo que implementamos.

Siguiendo planteando algunas preguntas más en su nombre:

Entonces, ¿qué ocurre si llamas a G.M(123) o, en el ejemplo original, si llamas a A.MyMethod(123) ?

Cuando la resolución de sobrecarga se enfrenta a dos métodos que tienen firmas idénticas debido a la construcción genérica, la construcción genérica se considera “menos específica” que la que es “natural”. Un método menos específico pierde a un método más específico.

Entonces, ¿por qué es una mala idea, si funciona la resolución de sobrecarga?

La situación con A.MyMethod no es tan mala; Por lo general, es bastante fácil determinar inequívocamente qué método se pretende. Pero la situación con G.M(123) es mucho peor. Las reglas de CLR hacen de este tipo de situación “comportamiento definido de implementación” y, por lo tanto, puede suceder cualquier cosa vieja. Técnicamente, el CLR podría negarse a verificar un progtwig que construye tipo G . O podría colapsar. En realidad, no lo hace; lo hace lo mejor que puede con la mala situación.

¿Hay algún ejemplo de este tipo de construcción de tipo que cause un verdadero comportamiento definido por la implementación?

Sí. Vea estos artículos para más detalles:

http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx

http://blogs.msdn.com/b/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx

Sí. MyMethod(int myVal) cuando el tipo del parámetro sea un int , se llamará a la sobrecarga genérica para todos los demás argumentos de parámetros, incluso cuando el argumento del parámetro sea implícitamente convertible a (o sea una clase derivada de) el tipo de hardcoded . La resolución de sobrecarga será la más adecuada, y la sobrecarga genérica se resolverá con una coincidencia exacta en el momento de la comstackción.

Nota: Puede invocar explícitamente la sobrecarga genérica y usar un int proporcionando el parámetro tipo en la llamada al método, como señala Steven Sudit en su respuesta.

 short s = 1; int i = s; MyMethod(s); // Generic MyMethod(i); // int MyMethod((int)s); // int MyMethod(1); // int MyMethod(1); // Generic** MyMethod(1.0); // Generic // etc. 

Sí lo son. Permitirán código como tal:

 A.MyMethod("a string"); // calls the generic version A.MyMethod(42); // calls the int version 

Sí, están sobrecargados. Se supone que el comstackdor prefiere las firmas de métodos explícitos contra los métodos generics si están disponibles. Sin embargo, tenga en cuenta que si puede evitar este tipo de sobrecarga, probablemente debería hacerlo. Ha habido informes de errores con respecto a este tipo de sobrecarga y comportamientos inesperados.

https://connect.microsoft.com/VisualStudio/feedback/details/522202/c-3-0-generic-overload-call-resolution-from-within-generic-function

Sí. Tienen el mismo nombre “MyMethod” pero diferentes firmas. La especificación C #, sin embargo, maneja específicamente esto diciendo que el comstackdor preferirá la versión no genérica sobre la versión genérica, cuando ambas son opciones.

Sí. Fuera de mi cabeza, si llamas a A.MyMethod(1); , siempre ejecutará el segundo método. Tendría que llamar a A.MyMethod(1); para forzarlo a ejecutar el primero.