Verwenden Sie nicht "statisch" in C #?

109

Ich reichte einen Antrag ein, den ich an einige andere Architekten zur Codeüberprüfung schrieb. Einer von ihnen schrieb mir fast sofort zurück und sagte: "Verwenden Sie nicht" statisch ". Sie können keine automatisierten Tests mit statischen Klassen und Methoden schreiben." Statisch "ist zu vermeiden."

Ich habe geprüft, und 1/4 meiner Klassen sind mit "statisch" gekennzeichnet. Ich verwende static, wenn ich keine Instanz einer Klasse erstellen möchte, da die Klasse eine einzelne globale Klasse ist, die im gesamten Code verwendet wird.

Er fuhr fort, etwas zu erwähnen, das Spott, IOC / DI-Techniken beinhaltet, die mit statischem Code nicht verwendet werden können. Er sagt, es sei bedauerlich, wenn Bibliotheken von Drittanbietern aufgrund ihrer Unprüfbarkeit statisch sind.

Ist dieser andere Architekt richtig?

Update: Hier ist ein Beispiel:

APIManager - In dieser Klasse werden Wörterbücher von Drittanbieter-APIs gespeichert, die ich zum nächsten zulässigen Zeitpunkt aufrufe. Es erzwingt API-Nutzungsbeschränkungen, die viele Drittanbieter in ihren Nutzungsbedingungen haben. Ich benutze es überall dort, wo ich einen Drittanbieter-Dienst anrufe, indem ich Thread.Sleep (APIManager.GetWait ("ProviderXYZ")) aufrufe. bevor Sie den Anruf tätigen. Alles hier ist threadsicher und es funktioniert hervorragend mit der TPL in C #.

Infin8Loop
quelle
37
staticist gut; static Felder müssen sehr sorgfältig behandelt werden
Marc Gravell
2
Warum sollte er Tests für Bibliotheken von Drittanbietern schreiben? Testen Sie in der Regel nicht einfach Ihren eigenen Code, vorausgesetzt, die Entwickler der Drittanbieter-Bibliothek haben ihre Tests durchgeführt?
Nope
3
Dieser spezielle Einwand ist mir etwas zu allgemein. In den meisten Fällen würden Sie die statische Klasse nicht mocj, Sie würden die Argumente verspotten. Statisches Feld, in dem es sich um eine aggregierte Klasse handelte, die verspottet werden musste, ja.
8
Offensichtlich haben Ihre Kollegen eine ernsthafte Erkrankung - einen akuten systemischen OOPus erythematodes. Sie brauchen eine Behandlung so schnell wie möglich!
SK-logic
6
Es gibt einen Abschnitt mit Antworten, ich verstehe nicht, warum die Leute einen Kommentar abgeben, um jemandem eine Antwort / einen Vorschlag zu geben. Es macht den Zweck des StackExchange zunichte. Ein Kommentar wäre sicherlich, mehr Informationen anzufordern.
Peteski

Antworten:

121

Es hängt davon ab, ob die statischen Klassen den Status beibehalten oder nicht. Persönlich habe ich kein Problem mit statusfreien Funktionen, die in einer statischen Klasse zusammengefasst sind.

Larsenal
quelle
111
Richtig. Statische Funktionen, die keine Nebenwirkungen haben, sind die prüfbarsten Funktionen von allen.
Robert Harvey
9
+1 dazu, aber mit einer Sicherheitsklausel: Fast jeder abstrakte Algorithmus ist zustandslos, aber das bedeutet nicht, dass Sie ihn als zustandslose statische Klasse oder Methode implementieren sollten. Wenn Sie es so implementieren, ist der gesamte Code, der es verwendet, kaum mit ihm verknüpft. Dies bedeutet beispielsweise, dass Sie, wenn Sie den Sortieralgorithmus als statische Methode implementieren und dann im Projekt verwenden , die Sortierung nicht vorübergehend durch einen anderen Algorithmus ersetzen können, z. B. zu Testzwecken und zur Eingrenzung des Problembereichs. Dies ist in vielen Fällen ein großes Hindernis. Abgesehen davon ist statisch völlig in Ordnung, wenn es vernünftig verwendet wird.
11
Kurz gesagt: Sie sind die testbarsten Funktionen, aber nicht unbedingt, sie machen den anderen Code testbarer! Das hat der Architekt wohl gemeint.
4
@ tereško: Die C # -Sprache erfordert, dass statische Methoden Teil einer statischen Klasse sind, wenn Sie keine Instanz der Klasse erstellen müssen, um die Methode aufzurufen. Vielleicht meinst du "Instanz" und nicht "Klasse".
Robert Harvey
8
@quetzalcoatl: Es ist vollkommen legal, einen Delegaten (dh einen anderen Algorithmus) an eine statische Methode zu übergeben. Die Erweiterungsmethoden in Linq sind alle statische Methoden. Beispiel: msdn.microsoft.com/en-us/library/…
Robert Harvey
93

Er ist zu allgemein. Er hat recht, es behindert das Testen. Allerdings staticKlassen und Methoden haben ihren Platz und es hängt wirklich vom Kontext ab . Ohne Codebeispiele kann man das nicht wirklich sagen.

Ich verwende static, wenn ich keine Instanz einer Klasse erstellen möchte, da die Klasse eine einzelne globale Klasse ist, die im gesamten Code verwendet wird.

Dies kann ein schwerer Codegeruch sein. Wofür benutzt du die Klassen? Daten speichern? Auf eine Datenbank zugreifen? Dann ist er richtig. In diesem Fall sollten Sie die Abhängigkeitsinjektion berücksichtigen, da eine solche statische Klasse praktisch ein impliziter Singleton ist.

Wenn Sie sie für Erweiterungsmethoden oder Hilfsprogramme verwenden, die den Status nicht ändern und nur die von Ihnen angegebenen Parameter verwenden, sind diese in der Regel in Ordnung.

Femaref
quelle
3
+1 für die Erwähnung, dass es sich um eine allgemeine Aussage handelte, und für die Erwähnung von Erweiterungsmethoden, die ebenfalls getestet werden können und über die meines Wissens immer noch Abhängigkeiten verspottet werden können.
Nope
4
Aye statisch als einzelne Klasseninstanz als implizite Singleton, das wird chaotisch ...
"Um auf eine Datenbank zuzugreifen?" warum nicht ? Wenn der Tabellenadapter nicht statisch ist, wird ein statischer Datensatz der Klasse @ mit starker Typisierung erstellt. Ist daran nichts auszusetzen?
Mathematik
27

Ich habe geprüft, und 1/4 meiner Klassen sind mit "statisch" gekennzeichnet. Ich verwende static, wenn ich keine Instanz einer Klasse erstellen möchte, da die Klasse eine einzelne globale Klasse ist, die im gesamten Code verwendet wird.

Das Beste, was Sie tun können, ist, Ihren Code zu testen und zu testen. Versuchen Sie, wiederholbare, unabhängige und einfache Tests zu entwerfen, und testen Sie jeweils nur eine Methode. Versuchen Sie, Ihre Tests in einer anderen zufälligen Reihenfolge durchzuführen. Kannst du einen stabilen "grünen" Build bekommen?

Wenn ja, ist dies ein gültiger Punkt, um Ihren Code zu verteidigen. Wenn Sie jedoch Schwierigkeiten haben, sollten Sie sich für instanzbasierte Methoden entscheiden.

oleksii
quelle
7
Dies ist der Punkt, der mich auch beeindruckt hat. Ein paar statische und zustandslose "Helfer" -Stilklassen sind in Ordnung, aber wenn Sie volle 25% aller Klassen als statisch haben, ist es unwahrscheinlich, dass sich Ihre Bemühungen auf diesen Fall beschränken.
Matthew Scharley
2
@MatthewScharley - er hat wahrscheinlich 4 Klassen, und eine von ihnen ist statisch :)
Alexus
1
Beachten Sie, dass die spätere Erstellung weiterer Instanzen schwierig sein kann, wenn Sie solche Stibcs (wie Singletons) verwenden. Wenn Sie beispielsweise eine Anwendung erstellen, die ein Dokument verarbeitet, treten später Probleme auf, wenn Sie mehrere Dokumente verwalten möchten.
Michel Keijzers
11

Die bereits geposteten Antworten decken viele wirklich gute Punkte ab, aber es gibt einen, der zu fehlen scheint:

Statische Felder werden niemals über den Müll gesammelt.

Dies ist sehr wichtig, wenn Sie eine App mit vielen Speicherbeschränkungen haben. Dieses Muster kann sehr häufig auftreten, wenn Benutzer versuchen, einen Cache zu implementieren.

Statische Funktionen sind bei weitem nicht so schlecht, aber alle anderen haben dies bereits ausführlich genug behandelt.

riwalk
quelle
10

Einer der Vorteile von IoC / DI besteht darin, dass die meisten Interaktionen zwischen Klassen zwischen Schnittstellen ausgehandelt werden. Dies erleichtert das Testen von Einheiten, da die Schnittstellen automatisch oder halbautomatisch nachgeahmt werden können und daher jedes der Teile auf Ein- und Ausgänge getestet werden kann. Über die Testbarkeit hinaus können Sie durch das Einfügen von Schnittstellen den modularsten Code erhalten - Sie können problemlos eine Implementierung ersetzen, ohne sich Sorgen machen zu müssen, dass Sie Abhängigkeiten vermasseln.

Da in C # keine Metaklassen vorhanden sind, kann eine Klasse keine Schnittstelle mit statischen Features implementieren, sodass statische Features von Klassen keine Anstrengungen unternehmen, um ein reines IoC / DI-Objektmodell zu implementieren. Das heißt, Sie können kein Mock erstellen, um sie zu testen, und Sie müssen echte Abhängigkeiten erstellen.

Wenn Ihr Unternehmen / Projekt stark in die Durchführung von IoC investiert ist, ist dies natürlich ein vernünftiges Anliegen, und der Schmerz, den Sie durchmachen, ist für den Gewinn aller. Vom architektonischen Standpunkt aus glaube ich jedoch nicht, dass man einem Modell bis ins Grab folgen sollte. Es gibt einige Dinge, die für die Implementierung mit statischen Methoden sinnvoll sind, z. B. die Singleton-Entwurfsstrategie. Ich selbst neige weniger zu statischen Klassen, weil ich glaube, dass sie die Vorteile von OO allmählich verlieren, aber manchmal ist eine Bibliotheksklasse wahrscheinlich ein natürlicherer Ausdruck von etwas als einer Engine.


Commenter erinnert mich an Erweiterungsmethoden, die sich in C # natürlich in statischen Klassen befinden müssen. Das ist legitim und ein Beispiel dafür, dass reines IoC in C # nicht besonders gut funktioniert, zumindest wenn Sie versuchen, die Breite der Sprache auszunutzen.

jwrush
quelle
1
Wenn eine Klasse aus den richtigen Gründen statisch gemacht und korrekt implementiert wird, wie zum Beispiel Erweiterungsmethoden, sind sie immer noch sehr testbar, da sie keine externen Abhängigkeiten aufweisen und in sich geschlossen sind und als solche keine Verspottung erfordern sollten. Sollte das Erfordernis einer Schnittstelle nicht von der Entwurfsanforderung abhängen, um eine Geschäftsanforderung bestmöglich zu erfüllen, und nicht, um ein reines IoC / DI-Projekt aufrechtzuerhalten?
Nope
1
Sie und ich sind uns einig, dass Sie das richtige Werkzeug für den richtigen Job auswählen und nicht von der Philosophie gefesselt werden sollten. Wenn jedoch in Ihrem Projekt für reines IoC / DI eine etablierte Kultur vorhanden ist, schadet dies genauso wie die Umstellung einer herkömmlichen Top-Down-Lösung auf IoC / DI. Das Engineering muss die Übergangskosten berücksichtigen. Im Übrigen glaube ich nicht, dass Erweiterungsmethoden Sie wirklich dahin bringen. Ich denke, eine bessere Lösung für IoCish-Verhalten mit statischen Klassen wäre die Auswahl mehrerer Klassen zur Kompilierungszeit mit Präprozessor-Direktiven, C-Stil
Jwrush
1
Äh. Ich bin dumm. Sie meinten eine statische Klasse für HOLDING-Erweiterungsmethoden, und natürlich müssen Sie diese so ausführen. Ja, natürlich möchten Sie zu diesem Zweck eine statische Klasse. Das ist mir durch den Kopf gegangen: und dies zeigt, dass C # nicht für IoC gedacht war. :)
Jwrush
Ja, Sie haben Recht, wenn eine bestehende Kultur in einem bestehenden Projekt existiert, wäre dies schädlicher, als dazu beizutragen, die Art und Weise zu ändern, wie Dinge getan werden.
Nope
5

Statische Klassen werden manchmal missbraucht und sollten sein:

  • ein Singleton (wobei die nicht statische Klasse ein statisches Element und eine öffentliche statische Instanzvariable hat, um sie nur einmal abzurufen / zu erstellen).
  • eine Methode in einer anderen Klasse (wo der Staat zählt). Wenn Sie ein Mitglied haben, das keine Daten aus dieser Klasse verwendet, sollte es wahrscheinlich nicht Teil dieser Klasse sein.

Es kann sich auch um eine sogenannte Utility-Funktion handeln, die Teil einer Utility-Klasse ist. Utility-Klassen sind Klassen, die nur statische Methoden enthalten und als Hilfsfunktionen ohne Kontext dienen.

Michel Keijzers
quelle
@topomorto Da die Klasse nicht durch ihren Konstruktor instanziiert werden sollte, was zu mehreren Objekten / Instanzen führt, sondern durch eine spezielle Methode (normalerweise instance ()) <, die immer dieselbe Instanz zurückgibt, die nach dem ersten Aufruf von instance () instanziiert wird.
Michel Keijzers
@topomorto Ich habe gerade geprüft, und Sie haben vollkommen recht, nur einige Mitglieder sind statisch (die Instanzvariable und die Instanzfunktion). Ich werde meine Antwort entsprechend ändern; danke fürs erwähnen.
Michel Keijzers
4

Statische Methoden sind in Ordnung und haben einen angemessenen Platz in der Programmierung. Es hört sich so an, als ob Ihr Architekt über ein Test-Framework verfügt, das statische Methoden nicht vollständig unterstützt. Wenn Ihr Code Teil eines größeren Projekts ist, ist es wichtig, die Architektenrichtlinien einzuhalten. Lassen Sie sich jedoch von diesem Projekt nicht davon abhalten, statische Methoden zu verwenden, wenn dies angemessen ist.

k Rey
quelle
1

Ich habe statische Eigenschaften für Dinge verwendet, die allen Instanzen einer Klasse gemeinsam sind. Und ich habe statische Methoden verwendet, um Gruppen von Klassenobjekten zu erhalten. Ich bin kein Experte, aber das hat bisher für mich funktioniert.

PHP Beispiel:

class vendorData {
  private static $data_table = 'vendor_data'; // static property
  private $id; // instance property
  private $name; // instance property

  public function __construct($vendor_id) {
    if(!self::validId($vendor_id) ) { // static method
      return false; // id doesn't exist
    }
    $this->id = $vendor_id; // id has been validated
    $this->getProperties(); // object method
  }

  private static function validId($vendor_id) {
    // send db query to find if the id exists
    // return true/false;
  }

  private function getProperties() { // object method
    $sql = "SELECT * FROM `{self::$data_table}` // using static property
        WHERE `id` = {$this->id}"; // using object instance property
    // get resultset
    foreach($result as $property => $value) {
      $this->$property = $value; // object instance properties all set
    }
  }

  // and here
  public static function getBy($property,$value) { // static method to return object array
    $sql = "SELECT `id` FROM `{self::$data_table}` // using static property
      WHERE `$property` = '$value'";
    // send query, get $ids array
    $obj_array = array();
    foreach($ids as $id) {
      // create array of current class objects using special static keyword
      // meaning of static here is different than in property/method declarations
      $obj_array[$id] = new static($id);
    }
    return $obj_array;
  }
}
Buttle Butkus
quelle
1

Ich sage, die Prinzipien, die sie haben, sind in Ordnung, aber die Aussage (verwenden Sie keine Statik) kann falsch sein. Wie hoch ist Ihre Codeabdeckung? Wenn die Anzahl hoch ist und Sie mit dem Komponententest Ihrer App vertraut sind, sind Sie in Ordnung. Wenn nicht, würde ich vorschlagen, den Code zu überprüfen. Sie können feststellen, dass statische Klassen der Grund sind oder nicht, es wird von vielen Dingen abhängen.


quelle
-3

Klassen mit statischen Methoden missbrauchen die Prinzipien von OOP. Es ist noch kein OOP, es ist COP - Klassenorientierte Programmierung.

Sie haben selten eine klare "Persönlichkeit" (ich verwende meine menschliche Lieblingsmetapher) hier) oder Identität. Sie wissen also nicht, wer sie sind. Dieser Punkt allein reicht aus, um dieses Konzept in OOP loszuwerden, aber es gibt noch mehr davon.

Der nächste ist eine Konsequenz des ersten Punktes. Da solche Klassen nicht wissen, wer sie sind, tendieren sie dazu, von groß bis riesig zu sein.

Dritte macht Ihren Code absolut nicht wartbar. Die Verwendung statischer Methoden führt zu versteckten Abhängigkeiten . Sie tauchen überall auf und Sie wissen nie, was in Ihrer Klasse passiert. Sie können sich nicht sicher sein, wenn Sie sich nur die Konstruktorsignatur ansehen.

Langsam, aber unvermeidlich, wird Ihr Code immer weniger zusammenhängend, da versteckte Abhängigkeiten schlecht kontrolliert werden. Sie scheinen unsichtbar zu sein. Und es ist so einfach, einen weiteren hinzuzufügen! Sie müssen die Signatur einer Methode nicht ändern. Sie müssen lediglich eine statische Methode aufrufen. Und was für ein hässlicher Code folgt ...

Ok, du hast es wahrscheinlich schon erraten. Eine enge Kopplung ist häufig mit einer geringen Kohäsion verbunden. Wenn viele Clients eine Klasse verwenden, wird die Kopplung enger. Und es ist eine große Verführung, eine bereits geschriebene Klasse oder Methode zu verwenden, die nur eine winzige Korrektur erfordert. Nur ein Methodenflag-Parameter.

Was anstelle von statischen Methoden verwenden? Nun, mein Vorschlag ist OOP. Warum nicht mal ausprobieren?

Zapadlo
quelle