Methode kann statisch gemacht werden, aber sollte es?

366

Resharper weist gerne auf mehrere Funktionen pro asp.net-Seite hin, die statisch gemacht werden könnten. Hilft es mir, wenn ich sie statisch mache? Soll ich sie statisch machen und in eine Utility-Klasse verschieben?

Dlamblin
quelle
20
Schreit Resharper nicht tatsächlich "geringer Zusammenhalt, geringer Zusammenhalt"? Es ist Zeit zu prüfen, ob die Methode wirklich zu dieser Klasse gehört.
PK
2
Mögliches Duplikat der Vorteile der Verwendung privater statischer Methoden
drzaus

Antworten:

245

Statische Methoden versus
Instanzmethoden 10.2.5 Statische und Instanzmitglieder der C # -Sprachenspezifikation erklären den Unterschied. Im Allgemeinen können statische Methoden eine sehr geringe Leistungssteigerung gegenüber Instanzmethoden bieten, jedoch nur in etwas extremen Situationen (siehe diese Antwort für weitere Details dazu).

Regel CA1822 in FxCop oder Code Analysis besagt:

"Nach [Markieren von Mitgliedern als statisch] sendet der Compiler nicht virtuelle Aufrufseiten an diese Mitglieder, wodurch zur Laufzeit für jeden Aufruf eine Überprüfung verhindert wird, die sicherstellt, dass der aktuelle Objektzeiger nicht null ist. Dies kann zu einem messbaren Leistungsgewinn führen In einigen Fällen stellt der Fehler beim Zugriff auf die aktuelle Objektinstanz ein Korrektheitsproblem dar. "

Utility-Klasse
Sie sollten sie nicht in eine Utility-Klasse verschieben, es sei denn, dies ist in Ihrem Entwurf sinnvoll. Wenn sich die statische Methode auf einen bestimmten Typ bezieht, wie sich eine ToRadians(double degrees)Methode auf eine Klasse bezieht, die Winkel darstellt, ist es sinnvoll, dass diese Methode als statisches Element dieses Typs existiert (beachten Sie, dass dies zu Demonstrationszwecken ein kompliziertes Beispiel ist).

Jeff Yates
quelle
2
> Der Compiler sendet nicht virtuelle Aufrufseiten an diese Mitglieder. Tatsächlich bedeutet dies, dass der Compiler möglicherweise ... ausgibt. Ich erinnere mich an etwas über den C # -Compiler, der callvirt anstelle von call verwendet, um einen potenziellen Fehler zu umgehen.
Jonathan Allen
24
Ich schneide es aus und füge es direkt aus FxCop 1.36 ein. Wenn FxCop falsch ist, fair genug.
Jeff Yates
5
@ Maxim Ich bin mir nicht sicher, ob ich die "Bullshit" -Aussage schätze. ziemlich unhöfliche Art, sich Fremden zu nähern. Der zugrunde liegende Punkt ist jedoch gültig; Ich habe die Dinge ein wenig aktualisiert (es war vor 9 Jahren, daher erinnere ich mich nicht an die Grundlage meiner ursprünglichen Behauptung).
Jeff Yates
10
@ Maxim Dein Punkt ist ungültig. Ich versichere Ihnen, dass ich vor 9 Jahren keine gute Bewertung hatte. Ich schätze Kommentare, die auf Fehler hinweisen (oder Änderungen, die sie korrigieren), aber seien Sie nicht unhöflich und stellen Sie keine unangemessenen Erwartungen an andere. Nennen Sie etwas nicht "Bullshit"; es impliziert die Absicht, Fehler oder Unwissenheit zu täuschen, anstatt ehrlich zu sein. Es ist unhöflich. Ich biete meine Zeit freiwillig an, um hier zu helfen, und es fühlt sich wirklich sinnlos an, wenn es mit Respektlosigkeit behandelt wird. Sag mir nicht, wovon ich beleidigt sein soll - das ist meine Wahl, nicht deine. Erfahren Sie, wie Sie Ihren Standpunkt mit Respekt und Integrität vertreten. Vielen Dank.
Jeff Yates
2
@Maxim Während Delegaten nicht neben jeder Instanz gespeichert werden, belegt jede Instanz einer zustandslosen Klasse tatsächlich etwas Speicher auf dem Heap, was einen unnötigen Overhead darstellt. Normalerweise ist das Instanziieren von Diensten nicht der Hot Path in einer Anwendung. Wenn Ihre Anwendung jedoch viele dieser Objekte erstellt, wird ein GC-Druck aufgebaut, der durch die einfache Verwendung statischer Methoden vermieden werden kann. Die ursprüngliche Behauptung des OP, dass statische Methoden in Extremsituationen einen Leistungsvorteil gegenüber zustandslosen Instanzen bieten, war angemessen nuanciert und gültig.
Asad Saeeduddin
259

Leistung, Verschmutzung des Namespace usw. sind meiner Ansicht nach zweitrangig. Fragen Sie sich, was logisch ist. Funktioniert die Methode logisch auf einer Instanz des Typs oder hängt sie mit dem Typ selbst zusammen? Wenn es das letztere ist, machen Sie es zu einer statischen Methode. Verschieben Sie es nur in eine Utility-Klasse, wenn es sich um einen Typ handelt, auf den Sie keinen Einfluss haben.

Manchmal gibt es Methoden , die logisch auf einer Instanz handeln , aber nicht passieren jede der Instanz des Staates zu verwenden , noch . Wenn Sie beispielsweise ein Dateisystem erstellen und das Konzept eines Verzeichnisses haben, es aber noch nicht implementiert haben, können Sie eine Eigenschaft schreiben, die die Art des Dateisystemobjekts zurückgibt, und es wäre immer gerecht "Datei" - aber es ist logisch mit der Instanz verbunden und sollte daher eine Instanzmethode sein. Dies ist auch wichtig, wenn Sie die Methode virtuell machen möchten - Ihre bestimmte Implementierung benötigt möglicherweise keinen Status, abgeleitete Klassen jedoch möglicherweise. (Wenn Sie beispielsweise eine Sammlung fragen, ob sie schreibgeschützt ist oder nicht, haben Sie möglicherweise noch keine schreibgeschützte Form dieser Sammlung implementiert, diese ist jedoch eindeutig eine Eigenschaft der Sammlung selbst und nicht des Typs.)

Jon Skeet
quelle
1
Ich würde denken, ein guter Linter sollte die Option haben, die Nachricht auf nicht virtuelle Methoden zu beschränken, da es für eine Basisklassenmethode sehr häufig ist, praktisch nichts zu tun. Override-Methoden würden normalerweise etwas bewirken, aber nicht immer. Manchmal ist es nützlich, eine Klasse für so etwas wie eine leere iEnumerable zu haben, deren Methoden die Instanz im Wesentlichen ignorieren, bei der die Instanz jedoch die richtige Methode auswählen muss.
Supercat
2
"Manchmal gibt es Methoden, die logisch auf eine Instanz einwirken, aber noch keinen Status der Instanz verwenden. Zum Beispiel" Ich habe Ihre Verwendung von "zum Beispiel" in dieser Instanz genossen.
PaulBinder
56

Markieren einer Methode als static innerhalb einer Klasse markieren, wird deutlich, dass keine Instanzmitglieder verwendet werden. Dies kann hilfreich sein, wenn Sie den Code durchblättern.

Sie müssen es nicht unbedingt in eine andere Klasse verschieben, es sei denn, es soll von einer anderen Klasse geteilt werden, die konzeptionell genauso eng miteinander verbunden ist.

Mark Cidade
quelle
22

Ich bin mir sicher, dass dies in Ihrem Fall nicht der Fall ist, aber ein "schlechter Geruch", den ich in einem Code gesehen habe, unter dem ich leiden musste, weil ich eine Menge statischer Methoden verwendet habe.

Leider handelte es sich um statische Methoden, die einen bestimmten Anwendungsstatus annahmen. (Warum sicher, wir haben nur einen Benutzer pro Anwendung! Warum sollte die Benutzerklasse dies nicht in statischen Variablen verfolgen?) Es handelte sich um verherrlichte Methoden für den Zugriff auf globale Variablen. Sie hatten auch statische Konstruktoren (!), Was fast immer eine schlechte Idee ist. (Ich weiß, dass es ein paar vernünftige Ausnahmen gibt).

Statische Methoden sind jedoch sehr nützlich, wenn sie Domänenlogik herausrechnen, die nicht vom Status einer Instanz des Objekts abhängt. Sie können Ihren Code viel lesbarer machen.

Stellen Sie nur sicher, dass Sie sie an der richtigen Stelle platzieren. Manipulieren die statischen Methoden auf intrusive Weise den internen Zustand anderer Objekte? Kann man gut behaupten, dass ihr Verhalten stattdessen zu einer dieser Klassen gehört? Wenn Sie Bedenken nicht richtig trennen, kann es später zu Kopfschmerzen kommen.

JasonTrue
quelle
4
Ihr Problem sind statische Felder / Eigenschaften, keine statischen Methoden.
Asad Saeeduddin
10

Das ist interessant zu lesen:

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

ReSharper schlägt nicht vor, dass Sie Ihre Methode statisch machen. Sie sollten sich fragen, warum diese Methode in dieser Klasse enthalten ist, im Gegensatz zu beispielsweise einer der Klassen, die in ihrer Signatur angezeigt werden ...

Aber hier ist, was resharper documentaion sagt: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static

pajics
quelle
2
Ich denke, dieser Punkt wird unterschätzt. Was das Tool Ihnen wirklich sagt, ist, dass die Methode nur auf die Mitglieder einiger anderer Klassen angewendet wird. Wenn es sich um eine Art Befehlsobjekt (oder "Anwendungsfall" oder "Interaktor") handelt, dessen Aufgabe es ist, andere Objekte zu manipulieren, ist das in Ordnung. Wenn jedoch nur eine andere Klasse manipuliert wird, klingt dies sehr nach Feature Envy .
Greg
9

Nur um die Antwort von @Jason True zu ergänzen , ist es wichtig zu wissen , dass das bloße Setzen von 'statisch' auf eine Methode nicht garantiert, dass die Methode 'rein' ist. Es wird in Bezug auf die Klasse, in der es deklariert ist, zustandslos sein, aber es kann durchaus auf andere 'statische' Objekte zugreifen, die einen Status haben (Anwendungskonfiguration usw.). Dies ist möglicherweise nicht immer eine schlechte Sache, aber einer der Gründe dafür Ich persönlich bevorzuge statische Methoden, wenn ich kann: Wenn sie rein sind, können Sie sie isoliert testen und begründen, ohne sich um den Umgebungszustand sorgen zu müssen.

Benjol
quelle
6

Sie sollten das tun, was in einem bestimmten Szenario am besten lesbar und intuitiv ist.

Das Leistungsargument ist nur in den extremsten Situationen gut, da das einzige, was tatsächlich passiert, ist, dass ein zusätzlicher Parameter ( this) zum Beispiel Methoden auf den Stapel geschoben wird.

Eric Schoonover
quelle
6

Für komplexe Logik innerhalb einer Klasse habe ich private statische Methoden gefunden, die beim Erstellen einer isolierten Logik nützlich sind, bei der die Instanzeingaben in der Methodensignatur klar definiert sind und keine Instanznebenwirkungen auftreten können. Alle Ausgänge müssen über Rückgabewert oder Out / Ref-Parameter erfolgen. Aufteilung der komplexen Logik in nebenwirkungsfreie Codeblöcke kann die Lesbarkeit des Codes und das Vertrauen des Entwicklungsteams in ihn verbessern.

Andererseits kann es zu einer Klasse kommen, die durch eine Vielzahl von Gebrauchsmethoden verschmutzt ist. Wie üblich können logische Benennung, Dokumentation und konsistente Anwendung von Teamcodierungskonventionen dies erleichtern.

G-Wiz
quelle
5

ReSharper überprüft die Logik nicht. Es wird nur geprüft, ob die Methode Instanzmitglieder verwendet. Wenn die Methode privat ist und nur von (möglicherweise nur einer) Instanzmethode aufgerufen wird, ist dies ein Zeichen dafür, dass sie eine Instanzmethode ist.

Brgerner
quelle
3

Wenn die Funktionen auf mehreren Seiten gemeinsam genutzt werden, können Sie sie auch in eine Basisseitenklasse einfügen und dann alle asp.net-Seiten, die diese Funktionalität verwenden, davon erben lassen (und die Funktionen können auch weiterhin statisch sein).

Mun
quelle
3

Wenn Sie eine Methode statisch machen, können Sie die Methode von außerhalb der Klasse aufrufen, ohne zuvor eine Instanz dieser Klasse zu erstellen. Dies ist hilfreich, wenn Sie mit Objekten oder Add-Ons von Drittanbietern arbeiten. Stellen Sie sich vor, Sie müssten zuerst ein Konsolenobjekt "con" erstellen, bevor Sie con.Writeline () aufrufen.

Austin
quelle
In Java müssten Sie eine Factory-Instanz erstellen, um das Konsolenobjekt zu erstellen, bevor Sie con.Writeline () aufrufen.
ScottMichaud
2

Es hilft, die Verschmutzung durch Namespaces zu kontrollieren.

Josh
quelle
8
Wie hilft eine statische Methode dabei, die Verschmutzung von Namespaces zu vermeiden?
Lockstock
1
Erfahrungsgemäß vermeiden Sie durch das Gruppieren von Methoden in Klassen mit statischen Methoden die Erfahrung, dass Sie den gesamten "Grab Bag" loser Funktionen voranstellen müssen, die möglicherweise mit anderen Bibliotheken oder integrierten Funktionen in Konflikt stehen. Mit statischen Methoden werden sie effektiv unter dem Klassennamen, z. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi
0

Nur meine Antwort: Wenn Sie einer Dienstprogrammklasse alle gemeinsam genutzten statischen Methoden hinzufügen, können Sie sie hinzufügen

using static className; 

zu Ihren using-Anweisungen, wodurch der Code schneller eingegeben und leichter gelesen werden kann. Zum Beispiel habe ich eine große Anzahl von sogenannten "globalen Variablen" in einem Code, den ich geerbt habe. Anstatt globale Variablen in einer Klasse zu erstellen, die eine Instanzklasse war, habe ich sie alle als statische Eigenschaften einer globalen Klasse festgelegt. Es erledigt den Job, wenn auch unordentlich, und ich kann die Eigenschaften nur nach Namen referenzieren, da auf den statischen Namespace bereits verwiesen wird.

Ich habe keine Ahnung, ob dies eine gute Praxis ist oder nicht. Ich muss so viel über C # 4/5 und so viel Legacy-Code lernen, dass ich nur versuche, mich von den Roselyn-Tipps leiten zu lassen.

Joey

Joseph Morgan
quelle
0

Ich hoffe, Sie haben den Unterschied zwischen statischen und Instanzmethoden bereits verstanden. Es kann auch eine lange und eine kurze Antwort geben. Lange Antworten geben bereits andere.

Meine kurze Antwort: Ja, Sie können sie in statische Methoden konvertieren, wenn Resharper dies vorschlägt. Das schadet nicht. Indem Sie die Methode statisch machen, schützen Sie die Methode tatsächlich so, dass Sie unnötigerweise keine Instanzmitglieder in diese Methode verschieben. Auf diese Weise können Sie ein OOP-Prinzip erreichen: " Minimieren Sie die Zugänglichkeit von Klassen und Mitgliedern ".

Wenn ReSharper vorschlägt, dass eine Instanzmethode in eine statische Methode konvertiert werden kann, heißt es tatsächlich: "Warum befindet sich diese Methode in dieser Klasse, da sie keinen ihrer Zustände verwendet?" Es gibt Ihnen also Denkanstöße. Dann können Sie erkennen, dass diese Methode in eine statische Dienstprogrammklasse verschoben werden muss oder nicht. Nach den SOLID-Prinzipien sollte eine Klasse nur eine Kernverantwortung haben. Auf diese Weise können Sie Ihre Klassen besser bereinigen. Manchmal benötigen Sie sogar in Ihrer Instanzklasse einige Hilfsmethoden. In diesem Fall können Sie sie in einem # region-Helfer aufbewahren.

Emran Hussain
quelle