2010-08-05 3 views
22

Je pense que cette question est mieux comprise par un exemple si on y va:Pourquoi une expression d'accès de base ne peut-elle pas être distribuée dynamiquement 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); 
     } 

    } 

Le compilateur indique clairement que la méthode C est invalide en raison du fait qu'il utilise un accès de base à appeler la méthode A. Mais pourquoi est-ce?

Et comment appeler la méthode de base lors du remplacement d'une méthode par des paramètres dynamiques?

E.g. si je voulais faire:

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

    } 

Répondre

19

Oui, cela ne peut pas fonctionner par conception. L'appel base.MethodA() effectue un appel non virtuel à une méthode virtuelle. Le compilateur a peu de difficulté à émettre l'IL pour cela dans le cas non dynamique puisqu'il sait quelle méthode spécifique doit être appelée.

Ce n'est pas le cas pour la répartition dynamique. C'est le travail du DLR de déterminer quelle méthode spécifique doit être appelée. Ce avec quoi il doit travailler est le MethodTable de la classe Derived. Cette table ne contient pas l'adresse de la méthode MethodA de la classe de base. Il a été écrasé par la dérogation. Tout ce qu'il peut éventuellement faire est d'appeler la méthode Derived.MethodA(). Ce qui viole le contrat de mot-clé de base.

+1

Ahh, enfin quelqu'un qui peut répondre à la * pourquoi *. Qu'entendez-vous par "Super classe"? Je connais seulement le terme comme étant synonyme de "classe de base". –

+0

@Allon: c'est dans l'extrait de l'OP. –

+0

@Hans: Oh, pfff, idiot moi. –

8

Dans votre exemple, Derived ne dispose pas d'une méthode nommée MethodA conséquent, l'appel base.MethodA() est la même chose que d'appeler this.MethodA(), de sorte que vous pouvez simplement appeler la méthode directement et être fait avec il. Mais je suppose que vous avez également un this.MethodA() différent et vous voulez être en mesure d'appeler base.MethodA(). Dans ce cas, il suffit d'écouter les conseils et jeter l'argument du compilateur à object (rappelez-vous que dynamic est vraiment juste object que les compilateur traite d'une manière spéciale):

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

Je suis assez sûr que l'appeler à travers la base est une exigence pour qu'il devienne une expression de base (ce qui est ma question). ;) L'utilisation de l'objet en tant qu'argument est la meilleure solution de contournement pour le moment, mais je cherche toujours une réponse à la question de savoir pourquoi je ne suis pas autorisé à transmettre une dynamique à une méthode de base. Quel est le vrai problème sous-jacent ici? –

-2

Vous pouvez utiliser ceci:

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

Spécification dit:

A de temps de liaison, une base d'accès expressions de la forme base.I et base [E] sont évalués exactement comme si ils ont été écrits ((B) this) .I et ((B) this) [E], où B est la classe de base de la classe ou structure dans laquelle la construction se produit

Donc, pourquoi votre exemple donne une erreur et cette construction compile bien c'est une bonne question.

+0

Je ne pense pas que cela fonctionnera toujours. Par exemple, si vous souhaitez appeler la méthode de la classe de base et que la méthode est marquée comme virtuelle, votre distribution entraînera l'appel de la méthode substituée à la place. –

+0

Oui, cela ne fonctionnera pas pour les méthodes virtuelles ... –

-1

Le problème n'est pas l'argument dynamique, mais l'appel utilise le DLR pour effectuer le dispatching (que l'exemple suivant illustre). Ce genre d'appel n'est peut-être pas appuyé par le 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

Ce n'est évidemment pas supporté, mais pourquoi? C'est la question ici. –

Questions connexes