C# - Warum sollte man static verwenden?

3 Antworten

Du fragst, warum man es nutzen sollte? Nun - sollte man nicht.

Es gibt nur sehr, sehr wenige Anwendungsfälle, wo es sinnvoll ist und die kann man fast immer auch anders umsetzen und spart sich dabei sogar noch die Nachteile von static.
Oder andersherum: Static macht nur Sinn, wenn das Programm schon vorher so schrecklich aufgebaut ist, dass die sinnvollen Alternativen (die ja manchmal eine gewisse Grunstruktur brauchen), nicht genutzt werden können.

Ich will hier jetzt keine zig Biespiele aufschreiben, die man am Ende immer auslegen kann, aber eine Faustregel kannst Du dir merken:

Verändert eine statische Methode irgendeinen statischen Zustand (z.B. statische Property), dann ist das tödlich!!!

Warum?
Weil keine Testbarkeit oder Austauschbarkeit, schwer zu trennende Abhängigkeiten, keine Flexibilität, etc. - sicher hab ich noch was vergessen.

Diese Nachteile gelten für alles, was statisch ist, aber bei globalen Variablen sind die besonders schwerwiegend.

Woher ich das weiß:Berufserfahrung – C#.NET Senior Softwareentwickler

Lamanini  02.06.2020, 22:15
Du fragst, warum man es nutzen sollte? Nun - sollte man nicht.

Das würde ich so nicht unterschreiben. Ich nutze es immer, wenn meine Funktionen keine Nebenwirkungen haben, und sich niemals ändern. Oder meine Variablen sich niemals ändern können.

Das gilt ja für ganz viel Mathematik, Distanzen werden immer gleich berechnet, ob jetzt von Punkt zu Punkt oder Punkt zu Gerade oder was auch immer.

Das gilt aber auch für irgendwelche Utilklassen die mir aus einem Array eine Liste machen oder sonst was.

Man sollte halt static nicht als Access-Modifier benutzen, dann geht das Schiff unter.

0
Palladin007  02.06.2020, 22:35
@Lamanini

Ja, mathematische Berechnungen sind vermutlich eine gute Ausnahme, das hab ich hier auch schon eingeräumt:

Es gibt immer wieder Fälle, wo das sinnvoll ist, mathematische Berechnungen wären so ein Beispiel, sieht man ja auch an der Math-Klasse.
Ich hab dazu Mal die Meinung gehört, dass solche Klassen nur dann "in Ordnung" sind, wenn man sie entweder nicht in anderen Projekten nutzt, oder für diese anderen Projekte den Code kopiert. Ob ich das so unterschreiben würde, da bin ich mir aber nicht so sicher.

Mit dem zweiten Absatz bin ich selber noch nicht so ganz glücklich (ich mag keinen duplizierten Code), aber das würde Probleme bei der Verwendung in mehreren Projekten umgehen. Hier muss man einfach abwägen, was weniger schlimm ist, denn schlimm ist beides.

Wahrscheinlich würde ich aber eher dazu tendieren, selbst solche Berechnungs-Klassen klassisch per DependencyInjection zu verteilen. Es mag vielleicht erst Mal unsinnig erscheinen, aber mir fallen durchaus Fälle ein, wo das sinnvoll sein kann
Wenn die Berechnungen sehr viel Leistung und Du sie plötzlich auf einem Server (mit viel mehr Rechenleistung) auslagern können möchtest, oder Du baust ein Caching für die Werte ein. Mit static würde das nicht gehen, da Du beidemale einen konkreten Zustand hast.

Static mag sinnvolle Fälle haben, aber die sind meiner Erfahrung nach nur sehr selten. Mir ist daher wichtig, dass die Sichtweise weg von "Was für Gründe gibt es gegen Static?" und mehr in Richtung "Was für Gründe gibt es für Static?" geht.

Ach ja:
Allermeistens sind die Gründe gegen Alternativen schlicht Faulheit :D
Und Faulheit lasse ich nicht durchgehen, da muss es schon um ein paar Stunden gesparte Zeit gehen und dann hat man ziemlich sicher andere Fehler gemacht.

1

Static kann an vielen Stellen Sinn machen, sollte aber mit Bedacht genutzt werden, da static prinzipiell etwas gegen die Prinzipien der Objektorientierung arbeitet (z.B. der Zuweisung von Funktionalität an ein Objekt).

Static kann aber beispielsweise Sinn machen, wenn du ein Singlepattern implementieren möchtest. Ein Singletonpattern könnte z.B. wie folgt aussehen:

public class Singleton
  {
    public static Singleton Instance { get; }

    static Singleton()
    {
      Instance = new Singleton();
    }

    private Singleton()
    { }

    public void InstanceMethod1() => Console.WriteLine("Ich bin eine Instanzmethode");

    public void InstanceMethod2() => Console.WriteLine("Ich bin auch eine Instanzmethode");
  } 

Durch dieses Muster hast du immer eine nur genau eine Instanz der Singleton-Klasse (auf der Property "Instance"), da die Klasse nicht außerhalb von sich selbst instanziiert werden kann und sich selbst nur beim ersten Zugriff auf sie instanziiert (Eigenschaft des statischen Konstruktors: Er wird nur ein einziges Mal beim ersten Zugriff auf die Klasse durchlaufen). Diese eine Anwendungs-weite Singletoninstanz kannst du dann in der ganzen Anwendung wie folgt abrufen und dessen Instanzmethoden verwenden:

public void SingletonTest()
    {
      Singleton.Instance.InstanceMethod1();
    }

Static benutze ich außerdem häufig für "Toolbox"-Klassen - also Klassen die allgemeine Funktionen bereitstellen um mir das Leben zu vereinfachen und einfach immer aufrufbar sein sollen ohne das ich explizit eine Instanz der Klasse erstellen muss. Außerdem macht z.B. auch in Anwendungsfällen Sinn, wo du zählen möchtest, wie oft ein Objekt bereits initialisiert wurde.

Ein besonderer Anwendungsfall sind Extensionmethoden - also Methoden mit denen du vorhandene Klassen dessen Quellcode dir nicht vorliegt erweitern möchtest. Z.B. so:

public static class ListExtensions
  {
    public static void PrintAllItems<T>(this List<T> items)
    {
      foreach (var item in items)
        Console.WriteLine(item);
    }
  }

Dadurch schaffst du dir die Möglichkeit die Methode "PrintAllItems" auf allen Objekten vom Typ List<T> aufzurufen:

public void ExtensionTest()
    {
      var list = new List<string>();
      list.PrintAllItems();
    }

Es gibt bestimmt noch tausende Anwendungsfälle für static und auch viele bei denen man auf static verzichten sollte, jedoch sind das so die Fälle in welchen ich static oft verwende.

Woher ich das weiß:Berufserfahrung

Palladin007  02.06.2020, 21:14

Singleton ließt man dabei häufig, doch ich frage mich da: Wo ist der Vorteil von Singleton gegenüber static?

Gut, man kann die Instanz weitergeben und ggf. mit Interfaces arbeiten, aber die tausend Abhängigkeiten gibt es immer noch und wirklich gut testen kann man die Klasse auch nicht.

Ich würde ein Singleton daher nur dann nutzen, wenn es aus z.B. technischen Gründen nicht anders geht.

Oder man nutzt Singleton in Verbindung mit IoC, da hat man die Vorteile, aber kaum Nachteile. Einziger Nachteil: Man muss umdenken und braucht eine gewisse Grundstruktur der Anwendung, aber daran gewöhnt man sich, wenn man es öffter macht.

0
ZWJezzy  02.06.2020, 21:29
@Palladin007

Ob und wann man Singletons oder statische Klassen verwenden sollte ist wie ich immer wieder lese quasi eine philosophische Frage. Hier habe ich ein paar Vergleiche gefunden, wann das eine bsser ist als das andere und umgekehrt:

https://www.c-sharpcorner.com/UploadFile/akkiraju/singleton-vs-static-classes/

Ich persönlich nutze Singletons immer um beispielsweise in einer WinForms-applikation globale Events bereitzustellen auf die jeder Controller (bei Nutzung vom MVC-Pattern) zugriff hat ohne irgendeinen anderen Controller zu kennen.

0
Palladin007  02.06.2020, 21:42
@ZWJezzy

Ja, Static vs. Singleton ist schon irgendwie philosophisch, wobei das Singleton natürlich Vorteile hat bzw. ein bisschen weniger scheiße ist :D
Was die Abhängigkeiten angeht, sind aber beide gleich schlimm, da man überall die selbe Klasse statisch nutzt und damit von ihr abhängig ist.

Ach und Thema globales statisches Event: Grausig! :D

Das scheit nach Memory Leaks, ich kann das Geschrei schon förmlich hören. Erst gestern hab ich in einem Forum eine Frage gelesen, wo jemand nach einem Weg gesucht hat, ob man Events von Außen "leeren" kann, weil die Anwendung von überall Events registriert, aber nicht korrekt aufgeräumt hat.

Außerdem tötest Du damit jede Testbarkeit. Kaum auszumahlen, was passiert, wenn zig Tests plötzlich aus zig Threads (UnitTests laufen asynchron) solche Events registrieren wollen oder noch schlimmer: Das Event wird plötzlich ausgeführt :D
Die Fehler, die Du dann bekommst, sind mit jedem Test-Run anders, ich wünsche dir viel Spaß beim fixen.

Aber wenn man es unbedingt braucht (warum auch immer), dann schau dir das EventAggregator-Pattern an, damit bist Du nicht nur viel flexibler, sondern kannst das Zeug sogar testen, indem jeder Test eine eigene EventAggregator-Instanz bekommt.

0
Palladin007  02.06.2020, 21:48

Ach ja:

ExtensionMethods sehe ich auch proebproblematisch.

Sie haben natürlich die selben Nachteile, wie statische Methoden, keine Frage.

Aber sie haben noch einen entscheidenden Nachteil:
Irgendwelche Methoden werden von irgendwo an Instanzen heran "geklebt", die vielleicht nicht Mal Sinn machen.
Oder man liest irgendwo eine Methode, sucht sie dann woanders und stellt fest, dass es sie plötzlich nicht mehr gibt. Das sorgt für Verwirrungen.

Ich hab die auch lange Zeit und sehr gerne genutzt, doch mitlerweile versuche ich es zu vermeiden, weil ich genau diese Probleme hatte.
Ich nutze sie eigentlich nur noch für Fälle, die man direkt erwarten würde, z.B. ein AddRange für ICollection<T>. Aber man sollte sehr vorsichtig mit sowas sein.

0

Z.b. Um Speicherplatz zu sparen. Static Variablen liegen nur genau einmal im Speicher und sind daher für jede Instanz gleich. Ist die Klasse static, muss sie nicht mal mehr instanzieiert werden


Palladin007  02.06.2020, 21:10

Mach halt ein Singleton (mit IoC) draus, damit verlierst Du alle Nachteile von Static und hast das Zeug auch nur einmal im RAM.

Abgesehen davon:
Wann sind die paar Bytes heute noch von Bedeutung?
Lesbarkeit, Wartbarkeit, Testbarkeit - das sind die großen Punkte, um die es in den meisten kommerziellen Projekten geht.

Wer unbedingt Performance optimieren will, der findet garantiert andere Stellen, die weit mehr bringen, als ein paar Byte weniger im RAM.
Abgesehen davon sollte man niemals die Performance "optimieren", ohne zu messen, ob das wirklich etwas bringt, denn Spoiler: Oft bringt das kaum was.

2
codinghelp  02.06.2020, 21:13
@Palladin007

Danke, das wusste ich so noch nicht. In unserer Vorlesung für Java kam es so rüber, als sei static eine gute Option die so oft wie möglich für Werte verwendet werden soll, die für alle Objekte gleich sind...

0
Palladin007  02.06.2020, 21:19
@codinghelp

Wenn sich diese Werte nicht ändern, also Konstanten, hast Du zwar immer noch die selben Nachteile, aber sie sind wenigstens nicht mehr so extrem gefährlich - zumindest solange sie readonly bleiben. Spoiler: Die bleiben selten readonly.

Aber egal wie Du es machst:
Jede Kleinigkeit hängt von diesen statischen Klassen ab und wenn Du aus irgendeinem Grund etwas daran ändern möchtest, dann hast Du Freude.

Wenn Du sowas brauchst, warum baut man kein sinnvolles Configuration- oder Options-Pattern drum herum? Microsoft hat mit ASP.NET Core tolle Frameworks dafür rausgehauen.
Du hast das gleiche Ergebnis: Überall sind die Werte verfügbar
Und Du hast einen entscheidenden Vorteil: Nichts ist mehr von der einen Klasse abhängig, Du kannst sie beliebig tauschen.

1
codinghelp  02.06.2020, 21:21
@Palladin007

Angenommen ich kenne die Vector2 Klasse nicht und brauche eine Funktion, die den Abstand zweier Punkte berechnet. Würde es sich hier nicht anbieten, eine statische Klasse mit dieser und ähnlichen Funktionen anzulegen?

0
Palladin007  02.06.2020, 21:33
@codinghelp

Kommt drauf an

Es gibt immer wieder Fälle, wo das sinnvoll ist, mathematische Berechnungen wären so ein Beispiel, sieht man ja auch an der Math-Klasse.
Ich hab dazu Mal die Meinung gehört, dass solche Klassen nur dann "in Ordnung" sind, wenn man sie entweder nicht in anderen Projekten nutzt, oder für diese anderen Projekte den Code kopiert. Ob ich das so unterschreiben würde, da bin ich mir aber nicht so sicher.

Wenn die Funktionen nun komplexer werden, kann es sinnvoller sein, eine Art Service daraus zu bauen:

public interface IMyComplexService
{
    Foo DoSomethingComplex(Bar bar);
}
public class MyComplexService : IMyComplexService
{
    public Foo DoSomethingComplex(Bar bar)
    {
        // ...
    }
}

Wenn Du das dann noch per DependencyInjection (z.B. mit IoC-Container) verteilst, hast Du die Möglichkeit, das zu tauschen.

Z.B. könnte es sein, dass Du für irgendein Programm z.B. Preis-Berechnungen so auslagern möchtest. Vielleicht gab es da auch Mal die Anforderung, dass es sich nicht ändern, aber dann soll es trotzdem geändert werden - irgendwann kommt das immer.
In diesem Fall hast Du mit so einem Service den Vorteil, dass Du mehrere Implementierungen je Situation einsetzen kannst.

Und selbst wenn Du es nie tauschen kannst, wenn Du eine Klasse wie die Folgende siehst:

public class FunnyClass
{
    public FunnyClass(IMyComplexService complexService)
    {
        // ...
    }
}

Dann weißt Du schon ohne den Code gesehen zu haben, was die Klasse braucht. Und Tests für diese Klasse können diesen Service gezielt verändern, um z.B. Fehlerfälle gezielt provozieren zu können.

1
Palladin007  02.06.2020, 21:52
@codinghelp

PS:

Es ist langfristig einfach sehr viel besser, wenn eine Klasse keinen Zugriff nach außen hinter einer Methode versteckt.
Nutzt eine Klasse Zeug von einer anderen Klasse, dann sorg dafür, dass man es der Klasse erst geben muss und lass nicht zu, dass sie von alleine dran kommt.

Das ist auch das Grundprinzip von DependencyInjection.
Inversion of Control denkt das sozusagen noch weiter und dreht die übliche Arbeit um, erzwingt aber dadurch auch eine Struktur, die gerade für kleine Projekte etwas overkill erscheinen mag.

1