12
votes

Aucun type d'inférence avec la méthode d'extension générique

J'ai la méthode suivante: xxx

et cette classe xxx p> maintenant, j'ai les problèmes suivants:

  1. Cette méthode d'extension montre sur tous les types, même chaîne .
  2. Je ne peux pas écrire nouvel événementInvocatorParameterers (evenabc). JUNTIL (E => FALSE); Il me dit "Les arguments de type pour la méthode ... ne peuvent pas être déduits de la Utilisation. "

    Je ne peux pas utiliser de paramètres de type générique comme celui-ci? Comment résoudre ce problème?
    Point important: J'ai besoin de ces deux paramètres génériques, car je dois renvoyer le même type que cette méthode d'extension a été appelée. <<


    image plus large (pas nécessaire pour répondre à la question!) :
    J'essaie de créer une interface fluide pour invoquer des événements. La base est cette classe statique: xxx

    Pour vous assurer que cette méthode ne peut être appelée que par des paramètres entièrement configurés, il n'accepte que un configureDeventInvocatorParamètres qui dérive de EventInvocatorParameters : xxx

    Les appels suivants seraient des appels valides: xxx

    Ce qui suit serait invalide: xxx

    pour effectuer ce travail, il existe des méthodes d'extension nommées avec , qui acceptent soit un EventHandler ou A TEventInvocatorParameterers et renvoie un ConfigurationDeventInvocatorParamètres . Tous les appels suivants avec avec doivent maintenant renvoyer le type configurationEventInvocatorParameters , sinon le deuxième exemple d'un appel valide (avec le jusqu'à à la fin) ne fonctionnerait pas.
    Si vous avez des idées sur l'API en général, faites-le-moi savoir. Cependant, je veux éviter les trois choses suivantes:

    • échoue uniquement au moment de l'exécution si les paramètres n'ont pas été configurés complètement
    • Création d'une syntaxe inverse comme EventName.with (...). Jusqu'à (...). Feu ()
    • Utilisez la méthode infâme do pour démarrer les choses: feu (eventName) .with (...). Jusqu'à (...). DO ();

0 commentaires

4 Réponses :


1
votes

y a-t-il une raison pour laquelle vous besoin em> utiliser une méthode d'extension? Si vous mettez jusqu'à code> sur la classe EventInvocatorParameters code> Vous pouvez éviter les deux problèmes mentionnés:

public class EventInvocatorParameters<T>
    where T : EventArgs
{
    public Func<T, bool> BreakCondition { get; set; }
    // Other properties used below omitted for brevity.

    public EventInvocatorParameters<T> Until (Func<T, bool> breakCond)
    {
        this.BreakCondition = breakCond;
        return this;
    }
}


1 commentaires

Oui, il y a une raison. Il est détaillé dans la longue durée de la question intitulée «Photo plus large (pas nécessaire pour répondre à la question!)». Peut-être que c'est nécessaire après tout. Version courte: jusqu'à ce que soit appelé une classe dérivée de EventInvocatorParameters et si tel est le cas, le type de retour de jusqu'à être ce type dérivé.



18
votes

mise à jour de novembre 2020 : la réponse originale ci-dessous a été écrite en 2011; Les règles de l'inférence de type de méthode générique, la résolution de la surcharge et la manière dont la "validation finale" des méthodes est effectuée ont eu de petites mais significatives changements dans les versions récentes de C #; Cette réponse et le lien vers un article archivé sur mon blog MSDN original à ce sujet ne peut plus être précis. En outre, Microsoft a supprimé les commentaires sur l'article original des raisons légales; Il y avait une énorme quantité de contexte et de discussion dans ces commentaires. J'espère à un moment donné le temps de revoir cet article pour clarifier (1) les règles d'aujourd'hui, (2) comment elles ont changé et (3) comment les idées discutées dans ces commentaires supprimés ont influencé ces décisions, mais c'est beaucoup de travail et je ne peux pas y arriver pendant un certain temps. N'oubliez pas que je n'ai pas été dans l'équipe de conception de la langue C # depuis novembre 2012.

Le type de méthode générique Inference fait délibérément pas apporter des déductions des contraintes. Les déductions sont plutôt fabriquées à partir des Arguments et les paramètres formels , puis les arguments de type déduites sont vérifiés contre les contraintes.

Pour une discussion détaillée de certains des problèmes de conception autour des contraintes et des signatures de méthode, y compris plusieurs dizaines de personnes qui me disent que je me trompe de penser que la conception existante est sensible, voir mon article sur le sujet:

HTTPS : //docs.microsoft.com/en-gb/archive/blogs/ericlippert/constraintS-Are-not-part-of-the-Signature


9 commentaires

J'ai aimé cette partie de votre réponse: "Y compris plusieurs dizaines de personnes me disant que je me trompe de penser que le design existant est sensible"! :-) Soins pour fournir une alternative qui atteint ce que je veux?


Et BTW: Je suis d'accord avec eux. Sans vouloir redémarrer cette discussion: ce que vous dites est le meilleur match pourrait être techniquement tellement, mais intuitivement, ce n'est pas le cas. Toutes les réponses vous disent que vous avez tort de faire suffisamment de preuve. Votre point principal est invalide à mon avis. Il n'y a pas de deviner. Je suis tout à fait d'accord avec la réponse de David Nelson à partir de 10 déc. 2009 16h13. Votre réponse à lui n'est pas plus convaincante. Le principal problème est que le compilateur déduit un type qui n'est pas valide pour cette méthode générique.


@Daniel: Le problème est que différents scénarios peuvent pomper votre intuition dans différentes directions. Je maintiens ma position: C # est une langue qui vous dit quand quelque chose semble mal. Il n'ignore pas de problème et redevient un choix pire lorsque le meilleur choix déduit violent une contrainte.


Je sais que vous maintenez votre position. Tous ces arguments ne pouvaient pas vous faire changer, alors pourquoi devriez-vous le mien? Cependant, vous pourrait améliorer la compréhension si vous fournissez un échantillon qui montre en réalité ce que vous percevez comme problème. Imaginez C # aurait été mis en œuvre l'inverse, quels scénarios ne manqueraient alors d'être intuitifs? Quelles erreurs et problèmes cela causerait-il? Parce que je - et évidemment beaucoup d'autres - ne voyez pas comment cela "ignorerait un problème".


J'ai toujours eu l'intuition que les contraintes ne feraient pas partie de la signature. Je ne suis pas capable de montrer cette intuition comme causant des problèmes si c'est faux. Mon intuition est basée sur le fait que je m'attends à ce que le mot «contrainte» implique de réduire le nombre d'appels de méthode légale que je puisse faire, plutôt que de changer ce que ces appels de méthode font. J'envisage d'utiliser une contrainte sur une méthode indéfinie pour une situation particulière, mais où l'appelant comme un étranger en regardant la signature de méthode semblerait autrement un sens. Prendre avec grain de sel; Je n'utilise pas beaucoup de contraintes.


Je l'aimerais s'ils pouvaient au moins permettre au polymorphisme basé sur des contraintes de type dans ce cas: Void Foo (T Barre T) où T: STRIT Void FOO (T Barre T) Où T: Classe


Imo, c'est une faille de conception. Si vous avez deux surcharges de méthode d'extension pour un type générique et que vous limitez la deuxième surcharge de type FOO, le compilateur n'est pas suffisamment intelligent pour sélectionner la première surcharge lorsque vous appelez à partir d'un objet source de type SPAM, mais il est assez intelligent de dire Vous que l'objet source ne correspond pas à la contrainte de type. L'ensemble de la raison des méthodes de vulgarisation est la commodité et il n'y a rien de pratique lorsque vous ne pouvez pas les utiliser car le compilateur n'est pas assez intelligent pour choisir la bonne surcharge, mais il est suffisamment intelligent de vous dire qu'il a choisi le mauvais.


L'article Eric lié n'est plus à cette URL. Il est disponible ici maintenant: docs.microsoft.com/en-gb/archive/blogs/ericlippert/...


@Matthewwatson: merci! Je finirai éventuellement à déplacer cela à Ericlippert.com, mais c'est un processus lent.




3
votes

Pour quiconque intéressé, pour l'instant, j'ai résolu le problème initial (API d'invocation de l'événement fluide) avec une hiérarchie générique de classe. C'est essentiellement la réponse de Hightichrider sur les stéroïdes.

Fire.Event(EventName.Until(e => false));
Fire.Event(EventName);


0 commentaires