2011-11-15 10 views
7

Acabo de tropezar con un problema muy interesante. Dando el siguiente código:Los métodos polimórficos no funcionan en C# 4

using System; 

class Program 
{ 
    class A { } 
    class B : A { } 

    private static void MyMethod(A a) /* first method */ 
    { 
     Console.WriteLine("A"); ; 
    } 

    private static void MyMethod(B b) /* second method */ 
    { 
     Console.WriteLine("B"); 
    } 

    static void Main(string[] args) 
    { 
     var a = new A(); 
     // Call first method 
     MyMethod(a); 

     A b = new B(); 
     // Should call the second method 
     MyMethod(b); 

     Console.ReadLine(); 
    } 
} 

yo esperaría que el segundo método se llama porque el tipo de tiempo de ejecución de la variable es B. Cualquier idea por qué el código llama el primer método en su lugar?

Gracias, Tibi

Algunas aclaraciones: El polimorfismo significa varias formas que no tiene nada que ver donde se declara el método.

Sobrecarga del método es una forma de polimorfismo, polimorfismo ad-hoc.

La forma en que el polimorfismo normalmente se implementa mediante el uso de encuadernación tardía.

dynamic es la solución para este problema.

El hecho es que esto no está funcionando en C# (o Java) es una decisión de diseño que me gustaría entender por qué se hizo, y ninguna de las respuestas está respondiendo a esta pregunta.

/Tibi

+4

Esto no es polimorfismo, tiene dos instancias sobrecargadas del mismo método, cada una teniendo diferentes tipos como parámetros. Luego declaras "b" como A. El compilador te permite hacer esto porque B hereda A. – Maess

Respuesta

6

La sobrecarga del método en C#, por defecto, se determina estáticamente en tiempo de compilación. Dado que está pasando una variable estáticamente estática de tipo A, vinculará estáticamente al método con la sobrecarga A. Use la palabra clave dinámica para obtener el comportamiento que desea.

static void Main(string[] args) 
{ 
    dynamic d = new A(); 
    // Call first method 
    MyMethod(d); 

    d = new B(); 
    // Call the second method 
    MyMethod(d); 

    Console.ReadLine(); 
} 
+0

¡No pensé en eso! Gracias. – Tibi

+0

En realidad, no era consciente de que la palabra clave 'dynamic' hace que las llamadas a métodos sobrecargados se resuelvan en tiempo de ejecución tampoco, esto es útil para saber. Sin embargo, tengo curiosidad sobre los posibles problemas de rendimiento con este tipo de enlace tardío. –

+1

Supongo que incurrirá en algunas visitas de rendimiento la primera vez que lo llame con un nuevo tipo de parámetro, ya que es necesario resolverlo, pero el DLR lo almacena en caché. – Tibi

14

Esto no es un ejemplo de polimorfismo en absoluto. El polimorfismo entra en juego cuando llamas los métodos al objeto, no cuando el objeto se usa como parámetro. Este es solo un ejemplo simple de sobrecarga de métodos.

Has declarado b como de tipo A, por lo que el compilador va a vincular a la sobrecarga que utiliza el tipo A. Al enlazador no le importa que B sea una subclase de A, simplemente selecciona la sobrecarga con la más cercana firma a los tipos declarados (no los tipos reales) de los parámetros pasados.

si desea forzarlo a utilizar el segundo método, envíe b in al tipo B en la llamada al método.

MyMethod((B)b); 
+0

De hecho. Lo mismo sucede en Java. Comportamiento esperado. – EdH

+0

En una situación más compleja, el casting podría hacer que el código sea feo. De todos modos, esperaría que el vinculador se preocupe por el tipo de parámetro y, en su lugar, use el enlace tardío. – Tibi

+1

Si desea que se comporte de esa manera, debe colocar el submenú 'DoSomething' en' A' y anularlo en 'B'. Luego, cuando llame a 'b.DoSomething()' elegirá la correcta según el tipo real. –

0

No está llamando el segundo método porque la referencia a b en sí es de tipo A. Mientras que b contiene una referencia a una instancia de B, no es un tipo real de B, por lo que se elige la sobrecarga que utiliza una referencia A.

+0

Entiendo exactamente lo que hace, simplemente no entiendo por qué. – Tibi

+1

Las llamadas a métodos se resuelven en tiempo de compilación. ('métodos dinámicos' tipos 'excluidos) Es por eso. – recursive

+0

Los métodos polimórficos se resuelven en tiempo de ejecución. – Tibi

Cuestiones relacionadas