2010-08-05 11 views
22

Creo que esta pregunta se entiende mejor con un ejemplo así que aquí vamos:¿Por qué no se puede distribuir dinámicamente una expresión de acceso base en C#?

public class Base { 

     // this method works fine 
     public void MethodA(dynamic input) { 
      // handle input 
     } 

    } 

    public class Derived: Base { // Derived was named Super in my original post 

     // This is also fine 
     public void MethodB(dynamic input) { 
      MethodA(input); 
     } 

     // This method does not compile and the compiler says: 
     // The call to method 'MethodA' needs to be dynamically dispatched, 
     // but cannot be because it is part of a base access expression. 
     // Consider casting the dynamic arguments or eliminating the base access. 
     public void MethodC(dynamic input) { 
      base.MethodA(input); 
     } 

    } 

El compilador establece claramente que el método C no es válida debido al hecho de que está usando el acceso base de llamar al método A. Pero por qué ¿es eso?

¿Y cómo se llama al método base al anular un método con parámetros dinámicos?

E.g. ¿y si lo que quería hacer:

public class Base { 

     // this method works fine 
     public virtual void MethodA(dynamic input) { 
      Console.WriteLine(input.say); 
     } 

    } 

    public class Derived: Base { // Derived was named Super in my original post 

     // this does not compile 
     public override void MethodA(dynamic input) { 
      //apply some filter on input 
      base.MethodA(input); 
     } 

    } 

Respuesta

19

Sí, esto no puede funcionar por diseño. La llamada base.MethodA() realiza una llamada no virtual a un método virtual. El compilador tiene pocos problemas para emitir el IL para esto en el caso no dinámico ya que sabe qué método específico necesita ser llamado.

Ese no es el caso para el envío dinámico. Es el trabajo del DLR averiguar qué método específico necesita ser llamado. Lo que tiene que trabajar con la clase MethodTable de la Derivada. Esa tabla no contiene que contiene la dirección del método 'MethodA' de la clase base. Fue sobrescrito por la anulación. Todo lo que posiblemente puede hacer es llamar al método Derived.MethodA(). Lo cual infringe el contrato de palabra clave básica.

+1

Ahh, finalmente alguien que puede responder el * por qué *. ¿Qué quieres decir con "Súper clase"? Solo sé que el término es sinónimo de "clase base". –

+0

@Allon: está en el fragmento del OP. –

+0

@Hans: Ah, pfff, tonto de mí. –

8

En su ejemplo, Derived no tiene un método MethodA nombrado, así que llamar base.MethodA() es lo mismo que llamar this.MethodA(), por lo que sólo puede llamar directamente al método y hacer con eso. Pero supongo que también tiene un this.MethodA() diferente y desea poder llamar al base.MethodA(). En este caso, sólo escuchar el consejo del compilador y el argumento a object (recordemos que dynamic es realmente sólo object que los compilador trata de una manera especial):

base.MethodA((object)input); 
+1

Estoy bastante seguro de que llamarlo a través de la base es un requisito para que se convierta en una expresión base (que es mi pregunta). ;) Utilizar el objeto como argumento es la mejor solución hasta el momento, pero aún así, estoy buscando una respuesta a por qué no puedo pasar un método dinámico a uno básico. ¿Cuál es el verdadero problema subyacente aquí? –

-2

Usted puede utilizar esto:

((Base)this).MethodA(input); 

Especificación dijo:

At-tiempo de unión, la base de acceso expresiones de los base.I de formulario y base [E] se evalúan exactamente como si se escribieron ((B) esto) .I y ((B) esto) [E], donde B es la clase base de la clase o estructura en la que construcción ocurre

Entonces, por qué su ejemplo da error y esta construcción se compila bien, es una buena pregunta.

+0

No creo que esto siempre funcione. Por ejemplo, si desea llamar al método de la clase base y el método está marcado como virtual, su conversión hará que se llame al método anulado. –

+0

Sí, esto no funcionará para métodos virtuales ... –

-1

El problema no es el argumento dinámico sino que la llamada utiliza el DLR para realizar el envío (que ilustra el siguiente ejemplo). Tal vez ese tipo de llamada no es compatible con el DLR.

public class Base 
{ 
    public virtual void Method(int input) 
    { 
    } 
} 

public class Super : Base 
{ 
    public override void Method(int input) 
    { 
     dynamic x = input; 
     base.Method(x); // invalid 
    } 
} 
+0

Evidentemente no es compatible, pero ¿por qué? Esa es la pregunta aquí. –

Cuestiones relacionadas