La méthode peut être rendue statique, mais devrait-elle l'être?

366

Resharper aime souligner plusieurs fonctions par page asp.net qui pourraient être rendues statiques. Est-ce que cela m'aide à les rendre statiques? Dois-je les rendre statiques et les déplacer vers une classe utilitaire?

dlamblin
la source
20
Resharper ne crie-t-il pas réellement «faible cohésion, faible cohésion»? il est temps de regarder si la méthode appartient vraiment à cette classe.
PK

Réponses:

245

Méthodes statiques et méthodes d'instance
10.2.5 Les membres statiques et d'instance de la spécification de langage C # expliquent la différence. Généralement, les méthodes statiques peuvent fournir une très petite amélioration des performances par rapport aux méthodes d'instance, mais uniquement dans des situations quelque peu extrêmes (voir cette réponse pour plus de détails à ce sujet).

La règle CA1822 dans FxCop ou l'analyse de code indique:

"Après [le marquage des membres comme statiques], le compilateur émettra des sites d'appels non virtuels vers ces membres, ce qui empêchera une vérification au moment de l'exécution pour chaque appel qui garantit que le pointeur d'objet actuel n'est pas nul. Cela peut entraîner un gain de performances mesurable pour le code sensible aux performances. Dans certains cas, l'échec de l'accès à l'instance d'objet actuelle représente un problème de correction. "

Classe utilitaire
Vous ne devez pas les déplacer vers une classe utilitaire à moins que cela ait du sens dans votre conception. Si la méthode statique se rapporte à un type particulier, comme une ToRadians(double degrees)méthode se rapporte à une classe représentant des angles, il est logique que cette méthode existe en tant que membre statique de ce type (notez qu'il s'agit d'un exemple compliqué à des fins de démonstration).

Jeff Yates
la source
2
> le compilateur émettra des sites d'appels non virtuels à ces membres En fait, c'est "le compilateur peut émettre ...". Je me souviens de quelque chose sur le compilateur C # utilisant callvirt au lieu d'appeler pour contourner un bug potentiel.
Jonathan Allen
24
Je l'ai coupé et collé directement à partir de FxCop 1.36. Si FxCop est faux, assez juste.
Jeff Yates
5
@Maxim Je ne suis pas sûr d'apprécier la déclaration "connerie"; façon assez grossière d'approcher des étrangers. Cependant, le point sous-jacent est valide; J'ai un peu mis à jour les choses (c'était il y a 9 ans, donc je ne me souviens pas du fondement de ma revendication d'origine).
Jeff Yates
10
@Maxim Votre point n'est pas valide. Je vous assure que je n'avais pas une bonne note il y a 9 ans. J'apprécie les commentaires qui signalent des erreurs (ou des modifications qui les corrigent), mais ne soyez pas impoli et ne mettez pas des attentes déraisonnables sur les autres. N'appelez pas quelque chose "connerie"; cela implique une intention de tromper plutôt qu'honnête à l'erreur ou à l'ignorance. C'est dur. Je donne de mon temps pour aider ici et c'est vraiment inutile quand il est traité avec irrespect. Ne me dites pas de quoi vous offenser - c'est mon choix, pas le vôtre. Apprenez à faire valoir votre point de vue avec respect et intégrité. Je vous remercie.
Jeff Yates
2
@Maxim Bien que les délégués ne soient pas stockés à côté de chaque instance, chaque instance d'une classe sans état occupe en effet de la mémoire sur le tas, ce qui est une surcharge inutile. Habituellement, l'instanciation des services n'est pas le chemin d'accès privilégié dans une application, mais si votre application finit par construire un grand nombre de ces objets, cela va créer une pression GC qui pourrait être évitée en utilisant simplement des méthodes statiques. L'affirmation originale du PO selon laquelle, dans des situations extrêmes, les méthodes statiques offrent un avantage en termes de performances par rapport aux instances sans état, était correctement nuancée et valide.
Asad Saeeduddin
259

Les performances, la pollution de l'espace de noms, etc. sont toutes secondaires à mon avis. Demandez-vous ce qui est logique. La méthode fonctionne-t-elle logiquement sur une instance du type ou est-elle liée au type lui-même? Si c'est le dernier, faites-en une méthode statique. Déplacez-le uniquement dans une classe utilitaire s'il est lié à un type qui n'est pas sous votre contrôle.

Parfois, il existe des méthodes qui agissent logiquement sur une instance mais qui n'utilisent pas encore l' état de l'instance . Par exemple, si vous construisez un système de fichiers et que vous avez le concept d'un répertoire, mais que vous ne l'avez pas encore implémenté, vous pouvez écrire une propriété renvoyant le type de l'objet du système de fichiers, et ce serait toujours juste "fichier" - mais il est logiquement lié à l'instance, et devrait donc être une méthode d'instance. Ceci est également important si vous souhaitez rendre la méthode virtuelle - votre implémentation particulière peut ne pas avoir besoin d'état, mais les classes dérivées le peuvent. (Par exemple, demander à une collection si elle est en lecture seule ou non - vous n'avez peut-être pas encore implémenté une forme en lecture seule de cette collection, mais c'est clairement une propriété de la collection elle-même, pas le type.)

Jon Skeet
la source
1
Je pense qu'un bon linter devrait avoir une option pour restreindre le message aux méthodes non virtuelles, car il serait très courant qu'une méthode de classe de base ne fasse pratiquement rien. Les méthodes de remplacement feraient généralement quelque chose, mais pas toujours. Parfois, il est utile d'avoir une classe pour quelque chose comme un iEnumerable vide, dont les méthodes ignorent essentiellement l'instance, mais où l'instance est requise pour sélectionner la bonne méthode à utiliser.
supercat
2
"Parfois, il existe des méthodes qui agissent logiquement sur une instance mais qui n'utilisent pas encore l'état de l'instance. Par exemple" J'ai apprécié votre utilisation de "par exemple" dans cette instance.
PaulBinder
56

En marquant une méthode comme staticdans une classe, il est évident qu'elle n'utilise aucun membre d'instance, ce qui peut être utile pour savoir quand parcourir le code.

Vous n'avez pas nécessairement à le déplacer vers une autre classe, sauf s'il est destiné à être partagé par une autre classe qui est tout aussi étroitement associée, conceptuellement.

Mark Cidade
la source
22

Je suis sûr que cela ne se produit pas dans votre cas, mais une "mauvaise odeur" que j'ai vue dans un code que j'ai dû souffrir en maintenant utilisé un tas de méthodes statiques.

Malheureusement, il s'agissait de méthodes statiques qui supposaient un état d'application particulier. (pourquoi bien sûr, nous n'aurons qu'un seul utilisateur par application! Pourquoi ne pas laisser la classe User garder une trace de cela dans les variables statiques?) Ils étaient des moyens glorifiés d'accéder aux variables globales. Ils avaient également des constructeurs statiques (!), Ce qui est presque toujours une mauvaise idée. (Je sais qu'il y a quelques exceptions raisonnables).

Cependant, les méthodes statiques sont très utiles lorsqu'elles tiennent compte de la logique du domaine qui ne dépend pas réellement de l'état d'une instance de l'objet. Ils peuvent rendre votre code beaucoup plus lisible.

Assurez-vous simplement de les mettre au bon endroit. Les méthodes statiques manipulent-elles de manière intrusive l'état interne d'autres objets? Peut-on démontrer que leur comportement appartient à l'une de ces classes? Si vous ne séparez pas correctement les préoccupations, vous pourriez avoir des maux de tête plus tard.

JasonTrue
la source
4
Votre problème concerne les champs / propriétés statiques, pas les méthodes statiques.
Asad Saeeduddin
10

Ceci est intéressant à lire:

http://thecuttingledge.com/?p=57

ReSharper ne suggère pas réellement que vous rendiez votre méthode statique. Vous devriez vous demander pourquoi cette méthode est dans cette classe par opposition à, disons, l'une des classes qui apparaît dans sa signature ...

mais voici ce que dit la documentation de resharper: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static

pyjics
la source
2
Je pense que ce point est sous-estimé. Ce que l'outil vous dit vraiment, c'est que la méthode ne fonctionne que sur certains membres d'une autre classe. Si c'est une sorte d'objet de commande (ou "cas d'utilisation" ou "interacteur"), qui a la responsabilité de manipuler d'autres objets, c'est bien. Cependant, si elle ne manipule qu'une seule autre classe, cela ressemble beaucoup à Feature Envy .
Greg
9

Juste pour ajouter à la réponse de @Jason True , il est important de réaliser que le simple fait de mettre 'statique' sur une méthode ne garantit pas que la méthode sera 'pure'. Il sera sans état en ce qui concerne la classe dans laquelle il est déclaré, mais il peut très bien accéder à d'autres objets `` statiques '' qui ont un état (configuration d'application, etc.), ce n'est pas toujours une mauvaise chose, mais l'une des raisons pour lesquelles Personnellement, j'ai tendance à préférer les méthodes statiques quand je peux, c'est que si elles sont pures, vous pouvez les tester et les raisonner isolément, sans avoir à vous soucier de l'état environnant.

Benjol
la source
6

Vous devez faire ce qui est le plus lisible et intuitif dans un scénario donné.

L'argument de performance n'est pas bon, sauf dans les situations les plus extrêmes, car la seule chose qui se passe réellement est qu'un paramètre supplémentaire ( this) est poussé sur la pile pour les méthodes d'instance.

Eric Schoonover
la source
6

Pour la logique complexe au sein d'une classe, j'ai trouvé des méthodes statiques privées utiles pour créer une logique isolée, dans laquelle les entrées d'instance sont clairement définies dans la signature de la méthode et aucun effet secondaire d'instance ne peut se produire. Toutes les sorties doivent être via la valeur de retour ou les paramètres out / ref. Décomposer une logique complexe en blocs de code sans effet secondaire peut améliorer la lisibilité du code et la confiance de l'équipe de développement en lui.

En revanche, elle peut conduire à une classe polluée par une prolifération de méthodes d'utilité. Comme d'habitude, la dénomination logique, la documentation et l'application cohérente des conventions de codage d'équipe peuvent atténuer ce problème.

G-Wiz
la source
5

ReSharper ne vérifie pas la logique. Il vérifie uniquement si la méthode utilise des membres d'instance. Si la méthode est privée et appelée uniquement par (peut-être une seule) méthodes d'instance, c'est un signe pour lui laisser une méthode d'instance.

brgerner
la source
3

Si les fonctions sont partagées sur plusieurs pages, vous pouvez également les placer dans une classe de page de base, puis faire hériter toutes les pages asp.net de cette fonctionnalité (et les fonctions peuvent toujours être statiques également).

Mun
la source
3

Rendre une méthode statique signifie que vous pouvez appeler la méthode depuis l'extérieur de la classe sans créer d'abord une instance de cette classe. Cela est utile lorsque vous travaillez avec des objets ou des modules complémentaires tiers. Imaginez si vous deviez d'abord créer un objet Console "con" avant d'appeler con.Writeline ();

Austin
la source
Java vous demanderait de créer une instance d'usine pour créer l'objet Console avant d'appeler con.Writeline ().
ScottMichaud
2

Il aide à contrôler la pollution de l'espace de noms.

Josh
la source
8
Comment le fait de rendre une méthode statique aide-t-il à éviter la pollution de l'espace de noms?
lockstock
1
Par expérience, en regroupant des méthodes dans des classes avec des méthodes statiques, vous évitez d'avoir à préfixer tous les "sacs à main" de fonctions lâches qui peuvent entrer en conflit avec d'autres bibliothèques ou fonctions intégrées. Avec les méthodes statiques, elles sont effectivement espacées sous le nom de classe, ex. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi
0

Juste ma tuppence: l'ajout de toutes les méthodes statiques partagées à une classe utilitaire vous permet d'ajouter

using static className; 

à vos instructions using, ce qui rend le code plus rapide à taper et plus facile à lire. Par exemple, j'ai un grand nombre de ce qu'on pourrait appeler des "variables globales" dans un code dont j'ai hérité. Plutôt que de créer des variables globales dans une classe qui était une classe d'instance, je les ai toutes définies comme propriétés statiques d'une classe globale. Il fait le travail, s'il est désordonné, et je peux simplement référencer les propriétés par nom car j'ai l'espace de noms statique déjà référencé.

Je ne sais pas si c'est une bonne pratique ou non. J'ai tellement de choses à apprendre sur C # 4/5 et tellement de code hérité à refactoriser que j'essaie simplement de me laisser guider par les conseils de Roselyn.

Joey

Joseph Morgan
la source
0

J'espère que vous avez déjà compris la différence entre les méthodes statiques et d'instance. En outre, il peut y avoir une réponse longue et une réponse courte. Des réponses longues sont déjà fournies par d'autres.

Ma réponse courte: Oui, vous pouvez les convertir en méthodes statiques si Resharper le suggère. Il n'y a aucun mal à le faire. Au contraire, en rendant la méthode statique, vous protégez réellement la méthode afin que, inutilement, vous ne glissiez aucun membre d'instance à cette méthode. De cette façon, vous pouvez réaliser un principe de POO " Minimiser l'accessibilité des classes et des membres ".

Lorsque ReSharper suggère qu'une méthode d'instance peut être convertie en une méthode statique, il vous dit en fait: "Pourquoi la .. cette méthode se trouve dans cette classe car elle n'utilise en fait aucun de ses états?" Donc, cela vous donne matière à réflexion. Ensuite, c'est vous qui pouvez réaliser le besoin de déplacer cette méthode vers une classe utilitaire statique ou non. Selon les principes SOLID, une classe ne devrait avoir qu'une seule responsabilité principale. Ainsi, vous pouvez faire un meilleur nettoyage de vos classes de cette façon. Parfois, vous avez besoin de certaines méthodes d'assistance, même dans votre classe d'instance. Si tel est le cas, vous pouvez les conserver dans un assistant #region.

Emran Hussain
la source