2010-01-29 12 views
9

supongamos que tenemos:resolución fin Método

public class FooBase 
{ 
    public void Write(byte value) 
    { 
     //something 
    } 

    public void Write(int value) 
    { 
     //something 
    } 
} 

public class Foo : FooBase 
{ 
    public void Write(decimal value) 
    { 
     //something 
    } 
} 

que esto:

 var writer = new Foo(); 

     writer.Write(5);   //calls Write(decimal) !! 
     writer.Write((byte)6); //calls Write(decimal) !! 

llamarán Escribir sobrecarga (decimal). ¿Por qué? ¿Y cómo puedo llamar a Write (int) o Write (byte)?

+0

Sugerir cambiar el nombre de la pregunta a algo que trata sobre "orden de resolución de método". – dss539

Respuesta

7

Se podría llamar Write(byte) así:

((FooBase)writer).Write((byte)6); 

Generalmente, C# preferiría utilizar una sobrecarga definido en el tipo directamente y emitir su argumento en lugar de utilizar una sobrecarga definido en un tipo de matriz.

Es un tipo de mal estilo tener un método que remeda un método de clase base de esta manera.

+0

Exactamente. La mejor solución es simplemente usar mejores nombres para evitar la ambigüedad. – captncraig

+0

Creo que eso está mal: cuando lanzas la instancia de escritor a la clase base, sigue siendo la misma instancia de clase derivada, por lo que se ejecutará su método sobrecargado. ¿Me estoy perdiendo de algo? – Isantipov

+0

Es una instancia, en la medida en que existe el objeto en la memoria. Sin embargo, al realizar un casting, le está diciendo efectivamente al compilador que trate esa instancia como otro tipo. El IDE ya no reconocería la sobrecarga tampoco. – EnderWiggin

16

Sí, hará eso. Este es efectivamente mi brainteaser #1. Esto no es realmente una inferencia de tipo en el sentido en que se usa normalmente, es la resolución de sobrecarga. Ahí es donde debes buscar en la especificación.

Ahora, el tipo de tiempo de compilación de Writer es Foo.

Cuando se llama a writer.Write, el compilador se iniciará con el tipo Foo y trabajar su camino hasta el tipo hiearchy hasta que encuentra un método declarado originalmente en ese tipo que pueda llamar legítimamente con los argumentos que le has dado. Tan pronto como encuentre uno, no irá más arriba en la jerarquía.

Ahora, 5 es convertible en decimal (y por lo tanto es de 5 después de haber sido lanzado específicamente para byte) - por lo que es un miembro de Foo.Write(decimal) función aplicable para su llamada al método - y eso es lo que se llama. Ni siquiera considera las sobrecargas FooBase.Write, porque ya se encuentra una coincidencia.

Hasta ahora, es razonable: la idea es que agregar un método al tipo base no debería cambiar la resolución de sobrecarga para el código existente donde el tipo secundario no lo conoce. Esto cae un poco cuando se trata de anulación. Vamos a cambiar su código levemente - Me voy a quitar la versión byte, hacer Write(int) virtual y anularlo en Foo:

public class FooBase 
{ 
    public virtual void Write(int value) 
    { 
     //something 
    } 
} 

public class Foo : FooBase 
{ 
    public override void Write(int value) 
    { 
     //something 
    } 

    public void Write(decimal value) 
    { 
     //something 
    } 
} 

ahora qué va a hacer new Foo().Write(5)? Será todavía llamada Foo.Write(decimal) - porque no Foo.Write(int)fue declarado en Foo, solamente anulados allí. Si cambia override a new, se invoca, porque eso cuenta como una nueva declaración de método.

Creo que ese aspecto es contra-intuitivo, y no es necesario para el control de versiones, como si estuviera anulando un método en la clase infantil, usted sabe claramente que está en la clase base.

La moraleja de la historia: intente no hacer esto. Terminarás confundiendo a la gente. Si deriva de una clase, no agregue nuevos métodos con el mismo nombre pero una firma diferente si es posible.

+0

Pensé en tu rompecabezas cuando también leí esta pregunta ... –

+0

+1 para la conclusión. No hagas esto – jeroenh