Avantages de l'utilisation de méthodes statiques privées


209

Lors de la création d'une classe qui possède des méthodes privées internes, généralement pour réduire la duplication de code, qui ne nécessite pas l'utilisation de champs d'instance, y a-t-il des avantages en termes de performances ou de mémoire à déclarer la méthode comme statique?

Exemple:

foreach (XmlElement element in xmlDoc.DocumentElement.SelectNodes("sample"))
{
    string first = GetInnerXml(element, ".//first");
    string second = GetInnerXml(element, ".//second");
    string third = GetInnerXml(element, ".//third");
}

...

private static string GetInnerXml(XmlElement element, string nodeName)
{
    return GetInnerXml(element, nodeName, null);
}

private static string GetInnerXml(XmlElement element, string nodeName, string defaultValue)
{
    XmlNode node = element.SelectSingleNode(nodeName);
    return node == null ? defaultValue : node.InnerXml;
}

Y a-t-il un avantage à déclarer les méthodes GetInnerXml () statiques? Pas de réponses d'opinion s'il vous plaît, j'ai une opinion.


Réponses:


221

De la page de règle FxCop sur ceci:

Après avoir marqué les méthodes comme statiques, le compilateur émettra des sites d'appels non virtuels à ces membres. L'émission de sites d'appels non virtuels 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 d'exactitude.


37
J'ajouterais également qu'une clause "statique" ne nuit pas et fournit déjà de la "documentation" avec 1 mot. Il vous indique que cette méthode n'utilise aucun membre d'instance, et vous obtenez cette documentation presque gratuitement
frandevel

20
J'irais jusqu'à dire: "Si une méthode n'a pas besoin d'un accès à l'état (ceci), rendez-la statique" en règle générale.
DanMan

3
Dans un souci d'équilibre, il convient de souligner que beaucoup de gens sont généralement contre les méthodes statiques car ils cassent le polymorphisme et signifient que l'objet ne peut pas être tronqué pour le test. par exemple, voir googletesting.blogspot.co.uk/2008/12/…
Andy

@ Andy - Bon point. Une façon de tracer la ligne serait de voir si la méthode statique accède à quelque chose en dehors des paramètres que vous transmettez. Tant qu'elle est autonome de cette manière, elle devrait être facile à tester, et il n'y a pas besoin pour écraser quoi que ce soit.
Neil

4
De nombreux développeurs ne sont pas familiers avec les "statiques privées". Je l'ai utilisé dans la base de code commune de mon équipe et cela a semé la confusion. En retour, il offre un avantage très mineur. Nous pourrions choisir d'éduquer tout le monde dans l'équipe, y compris tous les futurs développeurs qui maintiennent le code, sur ce que cela signifie. Mais l'avantage de passer d'une méthode privée à une statique privée est si mineur (c'est-à-dire supprimer la dépendance aux données d'instance), cela ne vaut pas l'effort et la confusion. La méthode est déjà de portée privée dans les deux cas. C'est une bizarrerie de langue qu'il n'est pas vraiment nécessaire de connaître.
Curtis Yallop

93

Lorsque j'écris une classe, la plupart des méthodes se répartissent en deux catégories:

  • Méthodes qui utilisent / modifient l'état de l'instance actuelle.
  • Méthodes d'assistance qui n'utilisent / ne modifient pas l'état de l'objet actuel, mais m'aident à calculer les valeurs dont j'ai besoin ailleurs.

Les méthodes statiques sont utiles, car rien qu'en regardant sa signature, vous savez que l'appel qu'il n'utilise ni ne modifie l'état de l'instance actuelle.

Prenez cet exemple:

Bibliothèque de classe publique
{
    Livre statique privé findBook (Liste des livres <Book>, titre de la chaîne)
    {
        // le code va ici
    }
}

Si une instance de l'état de la bibliothèque est jamais gâchée, et j'essaie de comprendre pourquoi, je peux exclure findBook comme coupable, juste à partir de sa signature.

J'essaie de communiquer autant que possible avec la signature d'une méthode ou d'une fonction, et c'est un excellent moyen de le faire.


1
Une sorte de déclaration de méthode const en C ++, n'est-ce pas?
anhoppe

Oui - c'est une autre bonne façon d'utiliser le langage pour simplifier les choses en limitant ce qui pourrait mal tourner.
Neil

Ce n'est pas nécessairement vrai. Supposons qu'un a Librarypossède un champ d'instance List<Book> _bookspour stocker ses livres (pas comment vous concevez Libraryprobablement une classe, mais avec / e), et il transmet cette liste à findBook, et cette méthode statique appelle books.Clear()ou books.Reverse()ainsi de suite. Si vous donnez à une méthode statique l'accès à une référence à un état mutable, cette méthode statique peut très bien gâcher votre état.
sara

1
Vrai. Et dans ce cas, la signature nous montrerait que cette méthode avait accès (et la possibilité de muter) à une instance de Library.
Neil

Pour pratiquement n'importe quelle construction protectrice que nous pourrions utiliser, il existe un moyen de la miner. Mais les utiliser est toujours sage et nous aide à nous pousser dans la bonne direction, vers le «gouffre du succès».
Neil

81

Un appel à une méthode statique génère une instruction d'appel en langage intermédiaire Microsoft (MSIL), tandis qu'un appel à une méthode d'instance génère une instruction callvirt, qui vérifie également les références d'objet nul. Cependant, la plupart du temps, la différence de performances entre les deux n'est pas significative.

src: MSDN - http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx


15

Oui, le compilateur n'a pas besoin de passer le thispointeur implicite aux staticméthodes. Même si vous ne l'utilisez pas dans votre méthode d'instance, elle est toujours transmise.


Comment cela est-il lié à un avantage de performances ou de mémoire lors de l'exécution?
Scott Dorman

11
Passer un paramètre supplémentaire signifie que le CPU doit faire un travail supplémentaire pour placer ce paramètre dans un registre et le pousser sur la pile si la méthode d'instance appelle une autre méthode.
Kent Boogaart, le

5

Ce sera un peu plus rapide car aucun paramètre n'est passé (bien que le coût de performance de l'appel de la méthode soit probablement bien supérieur à cette économie).

Je dirais que la meilleure raison pour laquelle je peux penser aux méthodes statiques privées est que cela signifie que vous ne pouvez pas modifier accidentellement l'objet (car il n'y a pas ce pointeur).


4

Cela vous oblige à vous souvenir de déclarer également tous les membres de portée de classe que la fonction utilise également statiques, ce qui devrait économiser la mémoire de création de ces éléments pour chaque instance.


Ce n'est pas parce qu'il s'agit d'une variable à portée de classe qu'elle doit être statique.
Scott Dorman,

3
Non, mais s'il est utilisé par une méthode statique, il DOIT être statique. Si la méthode n'était pas statique, il se peut que vous n'ayez pas rendu le membre de la classe statique, ce qui entraînerait davantage de mémoire utilisée pour chaque instance de la classe.
Joel Coehoorn

2

Je préfère de loin que toutes les méthodes privées soient statiques à moins qu'elles ne puissent vraiment pas l'être. Je préférerais de beaucoup ce qui suit:

public class MyClass
{
    private readonly MyDependency _dependency;

    public MyClass(MyDependency dependency)
    {
        _dependency = dependency;
    }

    public int CalculateHardStuff()
    {
        var intermediate = StepOne(_dependency);
        return StepTwo(intermediate);
    }

    private static int StepOne(MyDependency dependency)
    {
        return dependency.GetFirst3Primes().Sum();
    }

    private static int StepTwo(int intermediate)
    {
        return (intermediate + 5)/4;
    }
}

public class MyDependency
{
    public IEnumerable<int> GetFirst3Primes()
    {
        yield return 2;
        yield return 3;
        yield return 5;
    }
}

sur chaque méthode accédant au champ d'instance. Pourquoi est-ce? Parce que ce processus de calcul devient plus complexe et que la classe se retrouve avec 15 méthodes d'assistance privées, alors je veux vraiment pouvoir les extraire dans une nouvelle classe qui encapsule un sous-ensemble des étapes d'une manière sémantiquement significative.

Quand MyClassobtient plus de dépendances parce que nous avons besoin de la journalisation et que nous devons également informer un service Web (veuillez excuser les exemples de clichés), alors il est vraiment utile de voir facilement quelles méthodes ont quelles dépendances.

Des outils comme R # vous permettent d'extraire une classe d'un ensemble de méthodes statiques privées en quelques touches. Essayez de le faire lorsque toutes les méthodes d'assistance privées sont étroitement associées au champ d'instance et vous verrez que cela peut être un vrai casse-tête.


-3

Comme cela a déjà été dit, les méthodes statiques présentent de nombreux avantages. Toutefois; gardez à l'esprit qu'ils vivront sur le tas pendant la durée de vie de l'application. J'ai récemment passé une journée à rechercher une fuite de mémoire dans un service Windows ... la fuite était causée par des méthodes statiques privées dans une classe qui implémentait IDisposable et était invoquée de manière cohérente à partir d'une instruction using. Chaque fois que cette classe a été créée, la mémoire était réservée sur le tas pour les méthodes statiques au sein de la classe, malheureusement, lorsque la classe était supprimée, la mémoire pour les méthodes statiques n'était pas libérée. Cela a entraîné l'empreinte mémoire de ce service à consommer la mémoire disponible du serveur en quelques jours avec des résultats prévisibles.


4
Cela n'a aucun sens. Le tas ne stocke jamais de mémoire pour le code pour aucune méthode, statique ou autre. Le tas est destiné aux instances d'objet. Il y aura des données sur la pile pour tout appel de n'importe quelle méthode (pour conserver la mémoire pour les paramètres, la valeur de retour, les sections locales non hissées, etc.) mais tout cela disparaît lorsque la méthode termine son exécution.
Servy
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.