c# - metodos - Llamando a la sobrecarga del constructor cuando ambas sobrecargas tienen la misma firma
sobrecarga de metodos en java netbeans (4)
El hecho es que ambos no tienen la misma firma: uno está usando genéricos, mientras que el otro no.
Con esos métodos en su lugar, también podría llamarlo usando un objeto no int:
Foo<string> foo = new Foo<string>("Hello World");
Considere la siguiente clase,
class Foo
{
public Foo(int count)
{
/* .. */
}
public Foo(int count)
{
/* .. */
}
}
El código anterior no es válido y no se compilará. Ahora considera el siguiente código,
class Foo<T>
{
public Foo(int count)
{
/* .. */
}
public Foo(T t)
{
/* .. */
}
}
static void Main(string[] args)
{
Foo<int> foo = new Foo<int>(1);
}
El código anterior es válido y compila bien. Llama a Foo (cuenta int) .
Mi pregunta es si el primero no es válido, ¿cómo puede ser válido el segundo? Sé que la clase Foo <T> es válida porque T e int son tipos diferentes. Pero cuando se usa como Foo <int> foo = new Foo <int> (1) , T está obteniendo un tipo entero y ambos constructores tendrán la misma firma, ¿no? ¿Por qué el compilador no muestra el error en lugar de elegir una sobrecarga para ejecutar?
Eric Lippert blogged sobre esto recientemente.
No hay ambigüedad, porque el compilador elegirá la sobrecarga más específica de Foo(...)
que coincida. Como un método con un parámetro de tipo genérico se considera menos específico que un método no genérico correspondiente, Foo(T)
es, por lo tanto, menos específico que Foo(int)
cuando T == int
. En consecuencia, está invocando la sobrecarga de Foo(int)
.
Su primer caso (con dos definiciones de Foo(int)
) es un error porque el compilador permitirá solo una definición de un método con exactamente la misma firma, y usted tiene dos.
Su pregunta fue muy debatida cuando se diseñaron C # 2.0 y el sistema de tipo genérico en el CLR. ¡Tan acaloradamente, de hecho, que la especificación "vinculada" de C # 2.0 publicada por AW en realidad tiene la regla incorrecta! Hay cuatro posibilidades:
1) Hacer ilegal declarar una clase genérica que POSIBLEMENTE podría ser ambigua bajo ALGUNA construcción. (Esto es lo que la especificación de límite dice incorrectamente que es la regla). Por lo tanto, su declaración Foo<T>
sería ilegal.
2) Hacer que sea ilegal construir una clase genérica de una manera que crea una ambigüedad. declarar Foo<T>
sería legal, construir Foo<double>
sería legal, pero construir Foo<int>
sería ilegal.
3) Haga que todo sea legal y use trucos de resolución de sobrecarga para determinar si la versión genérica o no genérica es mejor. (Esto es lo que realmente hace C #).
4) Haz algo más que no haya pensado.
La regla # 1 es una mala idea porque hace que algunos escenarios comunes e inofensivos sean imposibles. Considere por ejemplo:
class C<T>
{
public C(T t) { ... } // construct a C that wraps a T
public C(Stream state) { ... } // construct a C based on some serialized state from disk
}
¿Quieres que sea ilegal solo porque C<Stream>
es ambiguo? Puaj La regla # 1 es una mala idea, así que la desechamos.
Desafortunadamente, no es tan simple como eso. IIRC las reglas de la CLI dicen que una implementación puede rechazarse como construcciones ilegales que realmente causan ambigüedades de firma. Es decir, las reglas de la CLI son algo así como la Regla # 2, mientras que C # en realidad implementa la Regla # 3. Lo que significa que, en teoría, podría haber programas legales de C # que se traduzcan en código ilegal, lo cual es profundamente desafortunado.
Para algunas reflexiones más sobre cómo este tipo de ambigüedades hacen que nuestras vidas sean miserables, aquí hay un par de artículos que escribí sobre el tema:
http://blogs.msdn.com/ericlippert/archive/2006/04/05/569085.aspx
http://blogs.msdn.com/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx