2012-07-04 10 views
6

Estaba probando los efectos de llamar a un miembro virtual en un constructor, y descubrí que al llamar a ese miembro, la excepción resultante se ajustaba a TargetInvocationException.¿Los miembros virtuales se llaman mediante reflejo (en circunstancias normales)?

De acuerdo con la docs esto es:

La excepción que se produce por métodos invocados por la reflexión

Sin embargo estoy al tanto de ninguna invokations a través de la reflexión. Entonces, ¿esto quiere decir que los miembros virtuales medios siempre se llaman a través de la reflexión? Si no, ¿por qué es así en este caso?

El código:

class ClassA 
    { 
     public ClassA() 
     { 
      SplitTheWords(); 
     } 

     public virtual void SplitTheWords() 
     { 
      //I've been overidden 
     } 
    } 

class ClassB : ClassA 
    { 
     private readonly String _output; 

     public ClassB() 
     { 
      _output = "Constructor has occured"; 
     } 

     public override void SplitTheWords() 
     { 
      String[] something = _output.Split(new[]{' '}); //TargetInvocationException! 
     } 
    } 

Respuesta

5

No, los métodos virtuales se llaman a través de virtual dispatch.

Reflection no se utiliza aquí. Y tampoco lo es para ninguna llamada a métodos virtuales. Creo que la documentación para la excepción es un poco engañosa ya que las excepciones de este tipo son lanzadas por métodos invocados a través de la reflexión, aunque no exclusivamente.

Si alguien tiene curiosidad sobre por qué el código en la pregunta da una excepción, es por el orden en que se ejecutan los constructores. El constructor ClassB es lo mismo que:

public ClassB() : base() 
{ 
    _output = "Constructor has occured"; 
} 

Nota de la llamada a base(), este llama al constructor de base antes de que se ejecute el ClassB constructor y, por lo tanto, antes de _output se asigna. Se llama al método virtual SplitTheWords en el constructor base, que se resuelve en ClassB.SplitTheWords. Este método intenta usar _output, de ahí el error.

Para obtener una visión más detallada de por qué los métodos virtuales no deberían llamarse desde los constructores this SO question tiene algo de información útil. Eric Lippert también tiene una muy buena publicación en el blog sobre por qué este es el caso here.

+1

+1 por "ligeramente engañoso", eso es algo profundamente confuso para los doctores. Se podría escribir una aplicación de consola que no hizo nada excepto 'throw new TargetInvocationException();' - ¿dónde estaría el reflejo entonces? – AakashM

+0

Entiendo _por qué_ los miembros virtuales no deberían ser llamados por los constructores, esto es lo que me impulsó a probar esto –

+0

@ m.edmondson Disculpas, entendí esto de su línea sobre 'Estaba probando los efectos de ...', no tenía la intención de que mi respuesta fuera condescendiente (pero creo que ahora puede ser así), simplemente incluí los últimos párrafos para que sean completos para otros que ven esta respuesta. Trataré de reformular. –

0

son miembros virtuales llamadas a través de la reflexión (en circunstancias normales)?

NO.

Ni de un constructor, por lo que está sucediendo algo más. Ayudaría a ver el código llamando al código que ha mostrado y al seguimiento de la pila de la excepción.

Cuestiones relacionadas