2010-07-16 32 views
9

Si tengo un SubOfParent clase que es una subclase de los padres, y dos métodos:pregunta básica sobre la sobrecarga de métodos

public static void doStuff(Parent in) {} 

public static void doStuff(SubOfPArent in) {} 

¿por qué el primera hacerTarea ser llamado al pasar un objeto de tipo SubOfParent ?

¡Gracias por cualquier idea sobre esto!

+0

http://stackoverflow.com/questions/479923/is-ca-single-dispatch-or-multiple-dispatch-language –

+0

Por favor, publique el código, de este contexto nadie tiene idea – Yakeen

+3

@Yakeen, aquí hay suficiente código para saber qué está mal. – tster

Respuesta

12
Parent p = new SubOfParent(); 
SubOfParent s = new SubOfParent(); 

doStuff(p); //calls doStuff(Parent in) 
doStuff(s); //calls doStuff(SubOfParent in) 

//If you're working with a parent but need to call the subclass, you need to upcast it. 
dostuff(p as SubOfParent); 
+0

gracias, esta totalmente clavada –

+4

Es obvio en este ejemplo que p es de tipo SubOfParent, pero ese no siempre será el caso. Para evitar sorpresas en doStuff, es mejor actualizar, verificar nulo y luego hacer la llamada. SubOfParent subOfParent = p como SubOfParent; if (subOfParent! = null) doStuff (subOfParent); –

+0

Esto tiene sentido en algunos casos, pero cuando se trata de usar la sobrecarga en un patrón de estrategia falla de manera miserable; por ejemplo, no puede hacer que el código elija automáticamente entre sobrecargas SubOfParent y SubOfParent2 dada una variable del tipo Parent que tiene asignado uno de los tipos derivados. – KeithS

8

la sobrecarga del método se realiza en tiempo de compilación, no en tiempo de ejecución, por lo que no verá ningún polimorfismo con ella. Independientemente del código de llamada que se conozca, el tipo que va a especificar especificará qué método se llama.

si desea llamar el segundo método que puede convertirlo al tipo SubOfPArent o en su lugar puede poner esos métodos en las clases y luego llamar a él para conseguir polimorfismo:

public class Parent 
{ 
    public virtual void doStuff() {} 
} 

public class SubOfPArent : Parent 
{ 
    public override void doStuff() {} 
} 

...

Parent obj = getASubOfPArent(); 
obj.doStuff(); 
+2

La pregunta se trata de funciones estáticas, no de funciones de instancia. – apoorv020

+1

@ apoorv020 tster todavía respondió la pregunta correctamente. Si bien es cierto que las sobrecargas de métodos estáticos se manejan de forma ligeramente diferente que los métodos de instancia, en este caso no hace la diferencia. –

+1

@ apoorv020, por eso dije que podía mover las funciones. Obviamente, estoy recomendando que cambie la forma en que se estructura el código. – tster

4

Probablemente haya llamado al método con una variable del tipo Parent.

Como las sobrecargas de métodos se resuelven en tiempo de compilación, el compilador solo puede seleccionar una sobrecarga basándose en los tipos de tiempo de compilación estáticos de los parámetros.

Por lo tanto, aunque su variable podría contener realmente una instancia SubOfParent en tiempo de ejecución, el compilador no lo sabe y, por lo tanto, elegirá la primera sobrecarga.

Los métodos virtuales, por el contrario, se resuelven en el tiempo de ejecución en función del tipo real de la instancia en cuestión.
Por lo tanto, si SubOfParent anulara un método virtual, llamar a ese método en una variable de tipo Parent llamaría correctamente al método reemplazado si la instancia es de hecho del tipo SubOfParent.

+0

Pasé SubOfParent - seguro. El método que llama a estos dos tiene si (a.GetType() == typeof (SubOfParent)) { hacerTarea (a); } else { doStuff (a); } y depuración a través del código, definitivamente pasa por la primera doStuff (a). –

+0

Ah, si tiene que escribir chequear, entonces sí, el * tiempo de ejecución * tipo podría ser 'SubOfParent' pero sospecho que el tipo de tiempo de compilación es' Parent' - en C# la opción de sobrecarga se define en tiempo de compilación. –

+0

Esa es la diferencia entre la sobrecarga de funciones y el despacho múltiple. –

0

Para llamar hacerTarea (SubOfPArent en) que necesita algo como esto:

SubOfPArent.doStuff (nueva SubOfPArent());

Pero creo que no sabes el tipo hasta el tiempo de ejecución ¿verdad?

Lo que dice tster es más elegante. Creo que eso es lo correcto.

0

Básicamente, el compilador resuelve qué método es llamada en un objeto (es decir, cuando ese objeto se pasa como un parámetro) en base a ese objeto de declarada tipo. Entonces, si tiene una variable escrita como Parent y la pasa a doStuff, el compilador resolverá que la llamada al método sea la sobrecarga tomando un Parent, incluso si en el tiempo de ejecución ese objeto resulta ser un SubOfParent.

Método llama por un objeto (es decir, métodos de instancia de una clase) polimorfismo exposición en tiempo de ejecución: el método ejecutado se basa en el objeto de real tipo.

Así que si usted ha tenido este:

class Parent 
{ 
    public virtual void doStuff() { } 
} 

class SubOfParent : Parent 
{ 
    public override void doStuff() { } 
} 

Parent p = new SubOfParent(); 
p.doStuff(); 

Entonces el código podría funcionar como se espera.

+0

Si 'Parent' y' SubOfParent' son (¿fueron?) Clases definidas por el usuario, sí, funcionaría. –

2

Creo que está lanzando a Parent en su código, o de otra manera proporcionando un tipo Parent. Por lo tanto, creo que el comportamiento es correcto y lo que espera que suceda es incorrecto.

Es correcto que ambas sobrecargas sean válidas para una referencia SubOfParent, pero la lógica de resolución de sobrecarga buscará métodos más específicos y, por lo tanto, debería encontrar la sobrecarga más específica.

SubOfParent p = new SubOfParent(); 

doStuff((Parent)p); // Calls base overload 
doStuff(p); // Calls specific overload 
1

sobrecarga de métodos se realiza en tiempo de compilación y por lo tanto depende del tipo estático en tiempo de compilación para determinar el método sobrecargado. En su ejemplo, podría pasar lo siguiente:

public static void Main(string[] args) 
{ 
    SubOfParent a = new SubOfParent(); 
    doStuff(a); // doStuff(SubOfParent) is called 
} 

El tipo estático de una en tiempo de compilación es SubOfParent, por lo que la sobrecarga esperada sería llamado.

public static void Main(string[] args) 
{ 
    Parent a = new SubOfParent(); 
    doStuff(a); // doStuff(Parent) is called 
} 

El tipo estático (el del tipo en la declaración) es Parent. En este caso, la otra versión sobrecargada se elegiría independientemente del valor que registre a.GetType() en tiempo de ejecución.

2

Si estás bien con el uso de la palabra clave dynamic, se podría pensar en hacer algo como esto:

private static void doStuffImpl(Parent obj) { 
    Console.WriteLine("I'm a Parent!"); 
} 

private static void doStuffImpl(SubOfParent obj) { 
    Console.WriteLine("I'm a Sub of Parent!"); 
} 

public static void doStuff(Parent obj) { 
    try { 
     doStuffImpl(obj as dynamic); 
    } 
    catch (RuntimeBinderException ex) { 
     // Not implemented ! 
    } 
} 

Podría ser útil si usted tiene una gran cantidad de sub clases.

doStuffImpl(obj as dynamic); se evaluarán en tiempo de ejecución. doStuffImpl se llamará con el tipo real obj.

0

puede sobrecargar funciones declarando función múltiple con el mismo nombre y diferentes argumentos

Cuestiones relacionadas