18 votos

Llamar sobrecarga del constructor cuando tanto la sobrecarga de tener la misma firma

Considere la siguiente clase

class Foo
{
    public Foo(int count)
    {
        /* .. */
    }

    public Foo(int count)
    {
        /* .. */
    }
}

Código anterior no es válido y no se compilará. Ahora, considere 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);
}

Código anterior es válido y compila bien. Se llama Foo(int count).

Mi pregunta es, si el primero no es válido, ¿cómo puede el segundo será válido? Sé la clase Foo<T> es válida debido a que T e int son de tipos diferentes. Pero cuando se utiliza como Foo<int> foo = new Foo<int>(1), T es la obtención de tipo entero y constructor será el mismo que el de la firma a la derecha? ¿Por qué no mostrar mensaje de error del compilador en lugar de elegir una sobrecarga a ejecutar?

23voto

John Feminella Puntos 116878

No hay ninguna ambigüedad, debido a que el compilador va a elegir el más específico de la sobrecarga de Foo(...) que coincide con. Desde un método con un parámetro de tipo genérico, se considera menos específica que la correspondiente a los no-método genérico, Foo(T) por lo tanto es menos específico que el Foo(int) cuando T == int. En consecuencia, usted es la invocación de la Foo(int) de sobrecarga.

Su primer caso (con dos Foo(int) definiciones) es un error, ya que el compilador va a permitir que una sola definición de un método, precisamente, con la misma firma, y tiene dos.

19voto

Eric Lippert Puntos 300275

Su pregunta fue muy debatido cuando C# 2.0 y el tipo genérico del sistema en el CLR fueron diseñados. Tan apasionadamente, en efecto, que el "obligado" de C# 2.0 especificación publicada por Una-W de la realidad tiene el mal de la regla en ella! Hay cuatro posibilidades:

1) Hacer que sea ilegal para declarar una clase genérica que podría ser ambigua, en virtud de ALGUNA construcción. (Esto es lo que el obligado spec incorrectamente dice que es la regla). Por lo que su Foo<T> declaración sería ilegal.

2) Hacer que sea ilegal para construir una clase genérica de una manera que crea una ambigüedad. declarando Foo<T> sería legal, construyendo Foo<double> sería legal, pero la construcción de Foo<int> sería ilegal.

3) Hacer todo legal y uso de la sobrecarga de la resolución de trucos para salir si el genérico o no genérico versión es mejor. (Esto es lo que C# en realidad tiene.)

4) Hacer algo más que yo no haya pensado.

Regla #1 es una mala idea, ya que hace algunos muy comunes y escenarios inofensivos imposible. Considerar, 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
}

Usted quiere que sea ilegal sólo porque C<Stream> es ambiguo? Puaj. Regla #1 es una mala idea, así que desechó.

Por desgracia, no es tan simple como eso. IIRC la CLI reglas dicen que una aplicación se permite rechazar como construcciones ilegales que de hecho no causa la firma de ambigüedades. Es decir, la CLI reglas son algo así como la Regla #2, mientras que C# en realidad implementa la Regla #3. Lo que significa que no podría ser, en teoría jurídica de los programas de C# que se traducen en ilegal de código, que es profundamente lamentable.

Para más ideas sobre cómo este tipo de ambigüedades que hacen que nuestra vida sea miserable, 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

9voto

Mike Two Puntos 16706

Eric Lippert, escribió en su blog acerca de esto últimamente.

0voto

DilbertDave Puntos 929

El hecho es que los dos no tienen la misma firma - uno es el uso de medicamentos genéricos, mientras que este otro no lo es.

Con esos métodos en el lugar que usted podría llamar también el uso de un no-objeto int:

Foo<string> foo = new Foo<string>("Hello World");

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X