Vorteile der Verwendung privater statischer Methoden

209

Gibt es beim Erstellen einer Klasse mit internen privaten Methoden, normalerweise um die Codeduplizierung zu reduzieren, für die keine Instanzfelder verwendet werden müssen, Leistungs- oder Speichervorteile, wenn die Methode als statisch deklariert wird?

Beispiel:

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

Gibt es einen Vorteil, wenn die GetInnerXml () -Methoden als statisch deklariert werden? Bitte keine Meinungsantworten, ich habe eine Meinung.

NerdFury
quelle
1
Ein mögliches Duplikat der Methode kann statisch gemacht werden, aber sollte es?
Drzaus

Antworten:

221

Auf der FxCop-Regelseite dazu:

Nachdem Sie die Methoden als statisch markiert haben, sendet der Compiler nicht virtuelle Aufrufseiten an diese Mitglieder. Durch das Ausgeben nicht virtueller Aufrufstandorte wird zur Laufzeit für jeden Aufruf eine Überprüfung verhindert, die sicherstellt, dass der aktuelle Objektzeiger nicht null ist. Dies kann zu einem messbaren Leistungsgewinn für leistungsabhängigen Code führen. In einigen Fällen stellt der Fehler beim Zugriff auf die aktuelle Objektinstanz ein Korrektheitsproblem dar.

Scott Dorman
quelle
37
Ich möchte auch hinzufügen, dass eine "statische" Klausel nicht schadet und bereits einige "Dokumentationen" mit 1 Wort enthält. Es sagt Ihnen, dass diese Methode kein Instanzmitglied verwendet, und Sie erhalten diese Dokumentation fast kostenlos
frandevel
20
Ich würde sogar sagen: "Wenn eine Methode keinen Statuszugriff benötigt (dies), machen Sie sie statisch", in der Regel.
DanMan
3
Im Interesse des Gleichgewichts ist darauf hinzuweisen, dass viele Menschen im Allgemeinen gegen statische Methoden sind, weil sie den Polymorphismus brechen und bedeuten, dass das Objekt nicht zum Testen gestoppt werden kann. Siehe zum Beispiel googletesting.blogspot.co.uk/2008/12/…
Andy
@ Andy - Guter Punkt. Eine Möglichkeit, die Grenze zu ziehen, besteht darin, zu prüfen, ob die statische Methode auf etwas außerhalb der von Ihnen übergebenen Parameter zugreift. Solange sie auf diese Weise in sich geschlossen ist, sollte sie leicht zu testen sein und es besteht keine Notwendigkeit etwas zu stummeln.
Neil
4
Viele Entwickler sind mit "Private Static" nicht vertraut. Ich habe es in der gemeinsamen Codebasis meines Teams verwendet und es hat zu Verwirrung geführt. Im Gegenzug bietet es nur einen sehr geringen Nutzen. Wir könnten uns dafür entscheiden, alle im Team, einschließlich aller zukünftigen Entwickler, die den Code pflegen, darüber zu informieren, was er bedeutet. Der Vorteil der Umstellung einer privaten Methode auf eine private statische Methode ist jedoch so gering (dh die Beseitigung der Abhängigkeit von den Instanzdaten), dass sich der Aufwand und die Verwirrung nicht lohnen. Die Methode ist in beiden Fällen bereits privat. Es ist eine Sprach-Eigenart, die man nicht unbedingt wissen muss.
Curtis Yallop
93

Wenn ich eine Klasse schreibe, fallen die meisten Methoden in zwei Kategorien:

  • Methoden, die den Status der aktuellen Instanz verwenden / ändern.
  • Hilfsmethoden, die den Status des aktuellen Objekts nicht verwenden / ändern, mir aber dabei helfen, Werte zu berechnen, die ich an anderer Stelle benötige.

Statische Methoden sind nützlich, da Sie nur anhand der Signatur erkennen, dass der Aufruf den Status der aktuellen Instanz nicht verwendet oder ändert.

Nehmen Sie dieses Beispiel:

öffentliche Klasse Bibliothek
{
    privates statisches Buch findBook (Liste <Book> Bücher, String-Titel)
    {
        // Code geht hier
    }}
}}

Wenn eine Instanz des Bibliothekszustands jemals durcheinander gerät und ich versuche herauszufinden, warum, kann ich findBook als Schuldigen nur anhand seiner Unterschrift ausschließen.

Ich versuche so viel wie möglich mit der Signatur einer Methode oder Funktion zu kommunizieren, und dies ist eine hervorragende Möglichkeit, dies zu tun.

Neil
quelle
1
Eine Art const-method-Deklaration in C ++, nicht wahr?
Anhoppe
Ja - das ist eine weitere gute Möglichkeit, die Sprache zu verwenden, um Dinge zu vereinfachen, indem begrenzt wird, was schief gehen könnte.
Neil
Dies ist nicht unbedingt wahr. Nehmen wir an, dass a Libraryein Instanzfeld List<Book> _bookszum Speichern seiner Bücher hat (nicht wie Sie Librarywahrscheinlich eine Klasse entwerfen würden, sondern w / e), und es übergibt diese Liste an findBookund diese statische Methode ruft books.Clear()oder books.Reverse()so weiter auf. Wenn Sie einer statischen Methode Zugriff auf einen Verweis auf einen veränderlichen Status gewähren, kann diese statische Methode Ihren Status sehr gut durcheinander bringen.
Sara
1
Wahr. In diesem Fall würde die Signatur zeigen, dass diese Methode Zugriff auf eine Instanz der Bibliothek hatte (und diese mutieren konnte).
Neil
Für praktisch jedes Schutzkonstrukt, das wir verwenden könnten, gibt es eine Möglichkeit, es zu untergraben. Aber sie zu benutzen ist immer noch klug und hilft uns, in die richtige Richtung in Richtung der "Grube des Erfolgs" zu treiben.
Neil
81

Ein Aufruf einer statischen Methode generiert eine Aufrufanweisung in der Microsoft Intermediate Language (MSIL), während ein Aufruf einer Instanzmethode eine callvirt-Anweisung generiert, die auch nach Null-Objektreferenzen sucht. Meistens ist der Leistungsunterschied zwischen beiden jedoch nicht signifikant.

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

Marek Takac
quelle
15

Ja, der Compiler muss den impliziten thisZeiger nicht an staticMethoden übergeben. Auch wenn Sie es in Ihrer Instanzmethode nicht verwenden, wird es dennoch übergeben.

Kent Boogaart
quelle
Wie hängt dies mit einem Leistungs- oder Speichervorteil zur Laufzeit zusammen?
Scott Dorman
11
Das Übergeben eines zusätzlichen Parameters bedeutet, dass die CPU zusätzliche Arbeit leisten muss, um diesen Parameter in einem Register abzulegen und auf den Stapel zu verschieben, wenn die Instanzmethode eine andere Methode aufruft.
Kent Boogaart
5

Es wird etwas schneller gehen, da dieser Parameter nicht übergeben wird (obwohl die Leistungskosten für den Aufruf der Methode wahrscheinlich erheblich höher sind als diese Einsparung).

Ich würde sagen, der beste Grund, den ich mir für private statische Methoden vorstellen kann, ist, dass Sie das Objekt nicht versehentlich ändern können (da es diesen Zeiger nicht gibt).

Kostenlose Gnus
quelle
4

Dies zwingt Sie dazu, sich daran zu erinnern, auch alle von der Funktion verwendeten Elemente mit Klassenbereich als statisch zu deklarieren, wodurch der Speicher für die Erstellung dieser Elemente für jede Instanz gespart werden sollte.

Joel Coehoorn
quelle
Nur weil es sich um eine Variable mit Klassenbereich handelt, bedeutet dies nicht, dass sie statisch sein sollte.
Scott Dorman
3
Nein, aber wenn es von einer statischen Methode verwendet wird, MUSS es statisch sein. Wenn die Methode nicht statisch wäre, hätten Sie das Klassenmitglied möglicherweise nicht statisch gemacht, und dies würde dazu führen, dass für jede Instanz der Klasse mehr Speicher verwendet wird.
Joel Coehoorn
2

Ich bevorzuge es sehr, dass alle privaten Methoden statisch sind, es sei denn, sie können es wirklich nicht. Ich würde Folgendes sehr bevorzugen:

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

über jede Methode, die auf das Instanzfeld zugreift. Warum ist das? Da dieser Berechnungsprozess komplexer wird und die Klasse 15 private Hilfsmethoden enthält, möchte ich sie WIRKLICH in eine neue Klasse ziehen können, die eine Teilmenge der Schritte auf semantisch sinnvolle Weise kapselt.

Wenn MyClassmehr Abhängigkeiten auftreten, weil wir protokollieren müssen und auch einen Webdienst benachrichtigen müssen (bitte entschuldigen Sie die Klischeebeispiele), ist es wirklich hilfreich, leicht zu erkennen, welche Methoden welche Abhängigkeiten haben.

Mit Tools wie R # können Sie eine Klasse mit wenigen Tastenanschlägen aus einer Reihe privater statischer Methoden extrahieren. Versuchen Sie es, wenn alle privaten Hilfsmethoden eng mit dem Instanzfeld verbunden sind und Sie feststellen, dass dies zu Kopfschmerzen führen kann.

Sara
quelle
-3

Wie bereits erwähnt, bieten statische Methoden viele Vorteile. Jedoch; Denken Sie daran, dass sie für die gesamte Lebensdauer der Anwendung auf dem Haufen leben werden. Ich habe vor kurzem einen Tag damit verbracht, einen Speicherverlust in einem Windows-Dienst aufzuspüren. Der Fehler wurde durch private statische Methoden in einer Klasse verursacht, die IDisposable implementiert hat und konsistent von einer using-Anweisung aufgerufen wurde. Jedes Mal, wenn diese Klasse erstellt wurde, wurde Speicher auf dem Heap für die statischen Methoden innerhalb der Klasse reserviert. Leider wurde der Speicher für die statischen Methoden nicht freigegeben, als die Klasse entsorgt wurde. Dies führte dazu, dass der Speicherbedarf dieses Dienstes innerhalb weniger Tage den verfügbaren Speicher des Servers mit vorhersehbaren Ergebnissen verbrauchte.

James Haumann
quelle
4
Das macht keinen Sinn. Der Heap nie speichert Speicher für den Code für jede Methode, statisch oder auf andere Weise. Der Heap ist für Objektinstanzen. Auf dem Stapel befinden sich Daten für jeden Aufruf einer Methode (um den Speicher für die Parameter, den Rückgabewert, nicht hochgezogene Lokale usw. zu speichern), aber all dies geht verloren, wenn die Ausführung der Methode abgeschlossen ist.
Servieren