7
votes

Les méthodes d'extension surchargeant en C #, fonctionnent-elles?

avoir une classe qui a une méthode, comme ceci: xxx pré>

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


1 commentaires

Ce que vous obtenez en outre est une architecture infinitivement mauvaise;) scnr


5 Réponses :


0
votes

Ce n'est pas possible (voir aussi MonkeyPatching pour les humains ) - peut-être avec DLR et méthodal_missing .


1 commentaires

Désolé, cette réponse est incorrecte. C'est possible. Voir les nombreuses autres réponses dans ce fil.



9
votes

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

expr.identifier ()

expr.identifier (args)

expr.identifier ()

expr.identifier (args)

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 . .

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) sera invoquée. La méthode d'instance est applicable si le paramètre sur window.display est un bouton ou est implicitement castable sur un bouton. Sinon, la méthode d'extension sera invoquée (car tout ce qui provient de objet est implicitement istable à un objet ).

donc, sauf s'il y ait un Un peu important que vous quittez, ce que vous essayez de faire fonctionnera.

Ainsi, considérez l'exemple suivant: xxx

ceci imprimera < / p> xxx

sur la console.


1 commentaires

w.display (b); // moulage implicite de sorte d'instance --- aurait dû être: --- w.display (** nab **); // coulé implicite alors instance



1
votes

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.

Selon ce Article :

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.

Êtes-vous sûr que vous passez explicitement un bouton?

ou est affichage de vide (bouton de bouton) vous appeler de manière récursive?


1 commentaires

+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 à objet . D'où la récursion.



0
votes

Eh bien, je crois que c'est un peu délicat. Si vous passez bouton en tant que paramètre de méthode: xxx

alors il y a une méthode de classe appropriée qui prime toujours la priorité sur la méthode d'extension.

mais Si vous passez un objet non , aucune méthode de classe appropriée et la méthode d'extension ne sera appelée. xxx

donc, de ce que je vois Votre exemple devrait fonctionner correctement et la méthode d'extension appellera Display sur la fenêtre instance. La boucle infinie peut être causée par un autre code.

y a-t-il de chances que fenêtre classe contenant affiche méthode dans votre exemple et classe qui est un paramètre à la méthode d'extension est en fait deux classes différentes?


5 commentaires

Sauf window.display (nouveau bouton ()); 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 doit appeler fenêtre.display (bouton) .


@Keith: hm


L'astuce ici est qu'il appelait window.display () 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 ()); 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.



2
votes

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


2 commentaires

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 ne se déclenche pas comme la meilleure correspondance, mais compilateur 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.