Flujo de ejecución de anulación de métodos y ocultación de métodos

Estoy confundido con el siguiente escenario, tenemos un conjunto de clases como este

public class A
{
    public virtual string SomeMethod()
    {
        return "A";
    }
}

public class B : A
{
    public override string SomeMethod()
    {
        return "B";
    }
}

public class C : B
{
    public new virtual string SomeMethod()
    {
        return "C";
    }
}

public class D : C
{
    public override string SomeMethod()
    {
        return "D";
    }
}

Cuando llamo al siguiente método

private void Test()
{
    A a = new D();
    B b = new D();
    C c = new D();
    D d = new D();
    Console.WriteLine(a.SomeMethod()); //The method in class B is being called
    Console.WriteLine(b.SomeMethod()); //The method in class B is being called
    Console.WriteLine(c.SomeMethod()); //The method in class D is being called
    Console.WriteLine(d.SomeMethod()); //The method in class D is being called
}

Estoy obteniendo la salida como esta

BBDD

¿Por qué se llama al método heredado, en lugar del método en el tipo declarado, y por qué el método no está en la clase? D siendo llamado cada vez?

preguntado el 27 de agosto de 12 a las 11:08

Respuesta corta: debido a la new palabra clave -

@BigYellowCactus, ¿puedes elaborar?

3 Respuestas

Cuando usted llama SomeMethod en una instancia de A (por ejemplo A foo = new <A or derived>()), espera obtener la versión más derivada de SomeMethod disponible. Ese es el punto de la herencia. Su código solo necesita tratar con instancias de la clase base, pero si esas instancias son realmente de una clase derivada, se invocan las implementaciones derivadas especiales. Este es el comportamiento que obtienes cuando anular un método.

Esto explica escenarios comunes como

A b = new B();
b.SomeMethod();  // B's implementation invoked

Con new, no está anulando el método, está declarando un método completamente nuevo con el mismo nombre. Este método existe solo en la clase que lo declaró y sus hijos, no es parte de las clases base y su cadena de herencia.

Entonces que hace A a = new D(); a.SomeMethod(); ¿hacer? La variable se declara como A, por lo que cualquier método/propiedad/etc invocado en su contra debe definirse en A. C definió un Un nuevo Método SomeMethod (y D lo anula), pero este método no existe en A, por lo que no se puede invocar aquí. La implementación más derivada de SomeMethod (como se declara en el tipo A) es en B, por lo que esta es la implementación que se invoca.

Misma historia para B b = new D(); b.SomeMethod();

Es solo cuando llegamos a C c = new D(); c.SomeMethod() que el Un nuevo El método tiene la oportunidad de ejecutarse. Esto se debe a que la variable es una C, y así el Un nuevo Método SomeMethod se declara por primera vez en el tipo de variable. Y como se indicó anteriormente, se invocará la versión más derivada posible, que en este caso significa la versión anulada por D.

Y espero que todos estemos en la misma página para D d = new D(); d.SomeMethod() :)

Otros han publicado buenos enlaces. Aquí hay otro hilo que podría ayudar: C # y ocultación de métodos

Y el último ejemplo aquí muestra un escenario aún más extraño en el que el método "nuevo" se declara como privado, por lo que otro tipo derivado en realidad hereda la versión base del método, en lugar de heredar la versión "nueva". http://msdn.microsoft.com/en-us/library/aa691135

contestado el 23 de mayo de 17 a las 11:05

"La variable se declara como A, por lo que cualquier método/propiedad/etc invocado contra ella debe definirse en A" si este es el caso, entonces ¿por qué A obj = new A(); obj.SomeMethod(); llamar al método en A y no llamar al método en B ? - Vamsi

Gracias obj es declarado e instanciado como A. Solo tiene que preocuparse por estas cosas cuando tiene una variable (o un argumento de método) que se declara como clase base, pero que se instancia como una clase derivada. - Latkin

Intento explicarlo de otra manera.

virtual / override significa que implementas / cambias el comportamiento del mismo método. es una implementacion de polimorfismo. Con new, crea un método completamente nuevo. Sucede que tiene la misma firma que otro método, pero no tiene nada que ver con eso.

Al llamar a estos métodos, depende del tipo que tenga la referencia (tipo de tiempo de compilación), para elegir el método que realmente llame.

Tu código es equivalente a:

public class A
{
    public virtual string SomeMethod()
    {
        return "A";
    }
}

public class B : A
{
    public override string SomeMethod()
    {
        return "B";
    }
}

public class C : B
{
    public virtual string AnotherMethod()
    {
        return "C";
    }
}

public class D : C
{
    public override string AnotherMethod()
    {
        return "D";
    }
}

private void Test()
{
    A a = new D();
    B b = new D();
    C c = new D();
    D d = new D();
    Console.WriteLine(a.SomeMethod()); //The method in class B is being called
    Console.WriteLine(b.SomeMethod()); //The method in class B is being called
    Console.WriteLine(c.AnotherMethod()); //The method in class D is being called
    Console.WriteLine(d.AnotherMethod()); //The method in class D is being called
}

El compilador elige llamar a AnotherMethod para referencia de tipo C (y D).

Respondido 30 ago 12, 06:08

"¿Por qué se llama al método heredado, en lugar del método en el tipo declarado?" - Vamsi

Ese es todo el sentido de la herencia y la anulación. Se llama polimorfismo: llamas a un método, el tipo (tiempo de ejecución) en sí mismo sabe qué hacer. es.wikipedia.org/wiki/… - stefan steinegger

Mi pregunta es esta si creo una instancia como esta A obj = new A(); y llama al método obj.SomeMethod(); la salida será A pero si inicializo la instancia de esta manera A objTest = new D(); y luego llamar al método objTest.SomeMethod(); saldrá B, Por qué está pasando esto ? - Vamsi

Porque en tiempo de ejecución, es una implementación de D. Por lo que ejecuta el SomeMethod implementación encontrada en D, que se hereda de B. new SomeMethod en su código que se implementa en C y D no se llama porque este es un método completamente diferente que solo tiene el mismo nombre. Eso es lo que trato de mostrar en mi código. - stefan steinegger

Ese es un comportamiento bien conocido: cuando ocultar método (con new) se llama solo cuando accede a él a través de una instancia de tipo oculto; cuando usa la instancia de la clase base, se usa el método original.

Ocultación no es anulación.

Respondido 27 ago 12, 11:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.