2010-08-05 5 views
22

Credo che a questa domanda si comprende meglio con un esempio così qui andiamo:Perché non è possibile inviare dinamicamente un'espressione di accesso di base in 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); 
     } 

    } 

Il compilatore afferma chiaramente che il metodo C non è valido a causa del fatto che sta utilizzando l'accesso di base di chiamare il metodo A. Ma perché è questo?

E come si chiama il metodo di base quando si esegue l'override di un metodo con parametri dinamici?

E.g. cosa succede se volevo fare:

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); 
     } 

    } 

risposta

19

Sì, questo non può funzionare in base alla progettazione. La chiamata base.MethodA() effettua una chiamata non virtuale a un metodo virtuale. Il compilatore ha pochi problemi a emettere l'IL per questo nel caso non dinamico poiché sa quale metodo specifico deve essere chiamato.

Questo non è il caso per la spedizione dinamica. È compito della DLR capire quale metodo specifico deve essere chiamato. Ciò su cui deve lavorare è la MethodTable della classe derivata. La tabella non contiene l'indirizzo del metodo MethodA della classe base. È stato sovrascritto dall'override. Tutto ciò che può fare è chiamare il metodo Derived.MethodA(). Che viola il contratto di parole chiave di base.

+1

Ah, finalmente qualcuno che può rispondere al * perché *. Cosa intendi per "super classe"? Conosco il termine solo come sinonimo di "classe base". –

+0

@ Allon: si trova nello snippet dell'OP. –

+0

@Hans: Oh, pfff, stupido. –

8

Nel tuo esempio, Derived non ha un metodo denominato MethodA, quindi chiamando base.MethodA() è lo stesso di chiamare this.MethodA(), così si può chiamare il metodo direttamente e da fare con esso. Ma suppongo che tu abbia anche un diverso this.MethodA() e tu voglia essere in grado di chiamare base.MethodA(). In questo caso, basta ascoltare il consiglio del compilatore e lanciare l'argomento per object (ricordiamo che dynamic è in realtà solo object che la tratta compilatore in modo speciale):

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

Sono quasi sicuro che chiamarlo tramite la base è un requisito per diventare un'espressione di base (che è la mia domanda). ;) L'utilizzo dell'oggetto come argomento è la soluzione migliore finora ma, tuttavia, sto cercando una risposta al motivo per cui non sono autorizzato a passare un metodo dinamico a un metodo base. Qual è il vero problema di base qui? –

-2

È possibile utilizzare questo:

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

Specifica detto:

Al legante il tempo, base-accesso espressioni dei base.I modulo e base [E] sono valutati esattamente come se fossero scritti ((B) questo) .I e ((B) questo) [E], dove B è la classe di base della classe o della struttura in cui il costruisce si verifica

Quindi, perché il tuo esempio dà errore e questa costruzione si compila bene è una buona domanda.

+0

Non penso che funzionerà sempre. Ad esempio, se si desidera chiamare il metodo della classe base e il metodo è contrassegnato come virtuale, il cast farà in modo che venga chiamato il metodo sottoposto a override. –

+0

Sì, questo non funzionerà con i metodi virtuali ... –

-1

Il problema non è l'argomento dinamico ma la chiamata utilizza il DLR per eseguire l'invio (che illustra il seguente esempio). Forse quel tipo di chiamata non è supportato dal 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

Ovviamente non è supportato, ma perché? Questa è la domanda qui. –

Problemi correlati