avoir une classe qui a une méthode, comme ceci: est-il possible de surcharger la méthode avec une autre qui est plus large, comme ceci: p> class WindowExtensions {
public void Display(this Window window, object o) {
Button button = BlahBlah(o);
window.Display(button);
}
}
5 Réponses :
Ce n'est pas possible (voir aussi MonkeyPatching pour les humains ) - peut-être avec DLR et méthodal_missing code>. p>
Désolé, cette réponse est incorrecte. C'est possible. Voir les nombreuses autres réponses dans ce fil.
Allons-y à la spécification. Premièrement, nous devons comprendre les règles des invocations de méthodes. À peu près, vous commencez avec le type indiqué par l'instance que vous essayez d'invoquer une méthode sur. Vous montrez la chaîne de héritage à la recherche d'une méthode accessible. Ensuite, vous faites vos règles de résolution de type et de surcharge et invoquez la méthode si cela réussit. Seulement si aucune méthode de ce type n'est trouvée, essayez-vous de traiter la méthode comme méthode d'extension. Donc, de l'§7.5.5.2 (Invocations de la méthode d'extension) Voir, en particulier, la déclaration en gras:
dans une invocation de méthode (§7.5.5.1) de l'une des formes p>
expr.identifier () code> p>
expr.identifier (args) code> p>
expr.identifier
() code> p>
expr.identifier
(args) code> p> Si le traitement normal de l'invocation ne trouve aucune méthode applicable, une tentative est faite pour traiter la construction en tant qu'invocation de méthode d'extension forte>. P>. BlockQuote>
Les règles au-delà de cela, obtenez un peu compliqué, mais pour le cas simple que vous nous avez présenté, c'est assez simple. S'il n'y a pas de méthode d'instance applicable, la méthode d'extension
windowextensions.display (fenêtre, objet) code> sera invoquée. La méthode d'instance est applicable si le paramètre sur
window.display code> est un bouton ou est implicitement fort> castable sur un bouton. Sinon, la méthode d'extension sera invoquée (car tout ce qui provient de
objet code> est implicitement istable à un objet
code>). P>
donc, sauf s'il y ait un Un peu important que vous quittez, ce que vous essayez de faire fonctionnera. p>
Ainsi, considérez l'exemple suivant: p>
xxx pré> ceci imprimera < / p>
xxx pré> sur la console. p> p>
w.display (b); // moulage implicite de sorte d'instance code> --- aurait dû être: ---
w.display (** nab **); // coulé implicite alors instance code>
Cela devrait fonctionner, le compilateur choisit presque toujours une méthode d'instance avec une signature acceptable sur une méthode d'extension avec la signature exacte. P>
Selon ce Article : P>
méthode d'instance avec un acceptable Signature à l'aide de la conversion d'élargissement sera presque toujours préféré sur une méthode d'extension avec un exact match de signature. Si cela se traduit par Lier à la méthode d'instance lorsque Vous voulez vraiment utiliser l'extension méthode, vous pouvez expliquer explicitement le Méthode d'extension utilisant le partagé Convention de la méthode appelante. C'est aussi la voie à désambiguë deux des méthodes qui ne sont pas plus spécifiques. p> blockQuote>
Êtes-vous sûr que vous passez explicitement un bouton? P>
ou est
affichage de vide (bouton de bouton) code> vous appeler de manière récursive? P>
+1, mais je pense que la question ici est "presque toujours préférée". À l'intérieur d'une méthode d'extension, il préfère lui-même, avec la forme implicite de la touche code> à
objet code>. D'où la récursion.
Eh bien, je crois que c'est un peu délicat. Si vous passez alors il y a une méthode de classe appropriée qui prime toujours la priorité sur la méthode d'extension. P> mais Si vous passez un objet non code> code>, aucune méthode de classe appropriée et la méthode d'extension ne sera appelée. p> donc, de ce que je vois Votre exemple devrait fonctionner correctement et la méthode d'extension appellera y a-t-il de chances que bouton code> en tant que paramètre de méthode:
Display code> sur la fenêtre code> code> instance. La boucle infinie peut être causée par un autre code. P>
fenêtre code> classe contenant
affiche code> méthode dans votre exemple et
code> classe qui est un paramètre à la méthode d'extension est en fait deux classes différentes? p> p>
Sauf window.display (nouveau bouton ()); code> appellera réellement la méthode de poste, c'est pourquoi il obtient la récursion infinie.
@Keith: Non, cela ne devrait pas; fenêtre.display (nouveau bouton ()) // La fenêtre est la fenêtre code> doit appeler
fenêtre.display (bouton) code>.
@Keith: hm
L'astuce ici est qu'il appelait window.display () code> de la méthode de poste pour obtenir la récursive.
@Jason: Je pense qu'il obtient la récursion parce que normalement window.display (nouveau bouton ()); code> frappe la méthode d'instance, mais à l'intérieur de la méthode d'extension, il se choisit à la place. J'ai vu des problèmes similaires à cela avant dans le compilateur C #, mais j'ai recréé cette question, alors pourrait avoir tort.
Il est possible, même si vous devez faire attention aux paramètres des surcharges - c'est généralement une bonne idée d'éviter les types d'objet code> tels que cela provoque souvent du code déroutant. Vous pouvez tomber faute de la façon amusante C # choisit les surcharges. Il choisira une correspondance «plus proche» avec des types pouvant être implicitement jetés sur une «autre» qui a des correspondances exactes (voir Cette question A>). class WindowExtensions
{
public void DisplayButton(this Window window, object o)
{
Button button = BlahBlah(o);
// now it's clear to the C# compiler and human readers
// that you want the instance method
window.Display(button);
}
}
Bon conseil pour changer le nom de la méthode. Mais si vous essayez d'exécuter l'exemple fourni par Jason, vous pouvez voir que la méthode d'extension code> ne se déclenche pas comme la meilleure correspondance, mais
compilateur code> choisit la méthode d'instance à invoquer de la méthode d'extension.
Ensuite, il ne faut pas obtenir l'erreur de récursion, mais de toute façon, je pense que les conseils sont: surcharges où les types des paramètres peuvent être dérivés les uns des autres sont toujours une mauvaise idée.
Ce que vous obtenez en outre est une architecture infinitivement mauvaise;) scnr