static kennzeichnet einen Member, der zum Typ gehört, nicht zu einem Objekt. Ein Instanzfeld existiert einmal pro Objekt; ein statisches Feld existiert einmal, Punkt. Eine Instanzmethode läuft auf einem Objekt (order.Ship()); eine statische Methode läuft auf dem Typ (Math.Round(x)) und braucht überhaupt kein Objekt.
Statische Felder: eine Kopie, geteilt
Am klarsten zeigt ein Zähler den Unterschied. Jede Order hat ihre eigene Id, aber die Anzahl der bisher erzeugten Bestellungen muss an einem gemeinsamen Ort liegen.
Ausgabe:
Ana #1, Ben #2, Chen #3
Orders created: 3
Auf statische Member wird über den Typnamen zugegriffen: Order.Created, nicht a.Created. C# erlaubt es nicht, einen statischen Member über eine Instanz zu erreichen (Fehler CS0176), was an der Aufrufstelle deutlich macht, dass der Wert geteilt ist.
Statische Methoden
Eine statische Methode hat kein this. Sie arbeitet nur mit ihren Parametern und anderen statischen Membern. Das macht sie zur natürlichen Form für Hilfsmethoden, die etwas aus ihren Eingaben berechnen:
Ausgabe:
61.38 EUR
7
Main selbst ist statisch: Die Runtime ruft es auf, bevor irgendein Objekt existiert.
Der Fehler CS0120: statischer Code verwendet Instanzmember
Weil Main statisch ist, stoßen Einsteiger auf diesen Fehler, sobald sie eine zweite Methode hinzufügen:
class Program
{
int visits;
void Greet() { Console.WriteLine("Hello"); }
static void Main()
{
Greet(); // error CS0120: An object reference is required for the non-static field, method, or property 'Program.Greet()'
visits++; // error CS0120: An object reference is required for the non-static field, method, or property 'Program.visits'
}
}
Eine statische Methode hat kein Objekt, es gibt also kein visits, das sie erhöhen könnte. Zwei Lösungen, und die richtige hängt davon ab, was der Member ist:
- Der Member sind wirklich Daten pro Objekt: Erzeuge ein Objekt und verwende es.
var app = new Program(); app.Greet(); - Der Member braucht keinen Objektzustand: Markiere ihn als
static.static void Greet() { ... }
Alles als static zu markieren, damit der Fehler verschwindet, funktioniert in einem winzigen Programm und wird in einem echten zu globalem Zustand. Entscheide anhand der Frage, ob die Daten zu einem Objekt oder zum ganzen Programm gehören.
Die umgekehrte Richtung ist immer erlaubt: Instanzmethoden können statische Member frei aufrufen.
Statische Klassen
Eine als static deklarierte Klasse darf nur statische Member enthalten und kann nie instanziiert werden. Sie ist eine benannte Gruppe von Funktionen und Konstanten.
Ausgabe:
77
100
True
Der Compiler setzt den Vertrag durch: Ein Instanzmember in einer statischen Klasse ist Fehler CS0708, und new darauf ist Fehler CS0712. Math, Console, File, Path und Enumerable sind alle statische Klassen. Auch Erweiterungsmethoden müssen in einer statischen Klasse stehen.
Statische Konstruktoren und static readonly
Ein statisches Feld, dessen Wert mehr als einen Ausdruck braucht, kann in einem statischen Konstruktor gesetzt werden, den die Runtime einmal ausführt, bevor der Typ zum ersten Mal verwendet wird:
Ausgabe:
Before first use
ShippingRates initialized
5.50
3
2026-01-01
readonly bedeutet, dass das Feld nur in seinem Initialisierer oder im statischen Konstruktor zugewiesen werden kann. Danach lässt es sich nicht neu zuweisen, auch wenn das Objekt, auf das es zeigt, noch veränderlich sein könnte, deshalb wird das Dictionary als IReadOnlyDictionary bereitgestellt.
const gegenüber static readonly
Beide geben dir einen benannten Wert, den das ganze Programm teilt, und sie unterscheiden sich darin, wann der Wert feststeht:
const | static readonly | |
|---|---|---|
| Wert steht fest | zur Kompilierzeit | zur Laufzeit, einmalig |
| Erlaubte Typen | Zahlen, char, bool, string, Enums, null | jeder Typ |
| Implizit statisch | ja (static const ist nicht erlaubt) | explizit als static deklariert |
| In aufrufende Assemblies kopiert | ja | nein, wird aus dem Feld gelesen |
In switch-Fällen und Attributargumenten verwendbar | ja | nein |
Die Zeile zum Kopieren zählt bei Bibliotheken: Deklariert Assembly A public const int MaxItems = 50; und verwendet Assembly B das, enthält B das Literal 50. A auf 100 zu ändern bewirkt für B nichts, bis B neu kompiliert wird. Für Werte, die sich zwischen Versionen ändern könnten, nimm lieber static readonly.
using static
Eine using static-Direktive (C# 6) importiert die statischen Member eines Typs, sodass du sie ohne den Typnamen aufrufen kannst:
Ausgabe:
Area: 28.27
40
Bei mathelastigem Code liest sich das gut. Anderswo nimm es sparsam: Ein nacktes WriteLine oder Parse verbirgt, von welchem Typ die Methode kommt.
Statischer Zustand und Threads
Ein statisches Feld wird von jedem Thread im Prozess geteilt. Es aus mehreren Threads gleichzeitig zu erhöhen verliert Aktualisierungen, weil created++ ein Lesen, ein Addieren und ein Schreiben ist und zwei Threads diese verschränken können. Nimm Interlocked.Increment(ref created) für Zähler oder einen Lock für alles Größere. Webanwendungen sind der übliche Ort, an dem das zubeißt: Jede Anfrage läuft auf irgendeinem Thread, ein statisches Feld mit „dem aktuellen Benutzer“ wird also von allen Benutzern geteilt.
Noch eine Feinheit: In einer generischen Klasse bekommt jeder konstruierte Typ seine eigenen statischen Felder. Cache<int>.Count und Cache<string>.Count sind zwei verschiedene Felder.
Wann static passt
Gute Einsätze:
- Reine Hilfsmethoden, die ein Ergebnis aus ihren Argumenten berechnen: Formatierung, Umwandlungen, Validierung.
- Konstanten und schreibgeschützte Nachschlagedaten, die das Programm teilt.
- Fabrikmethoden wie
TimeSpan.FromMinutes(5)oder dein eigenesTemperature.FromCelsius(21). - Erweiterungsmethoden.
Schlechte Einsätze:
- Veränderlicher globaler Zustand (der aktuelle Benutzer, ein Warenkorb, Einstellungen, die sich ändern). Er koppelt jedes Codestück, das ihn berührt, und macht Tests von den Überbleibseln anderer Tests abhängig.
- Alles, was du in Tests austauschen willst, etwa eine Uhr, eine Datenbank oder einen E-Mail-Versender. Statische Aufrufe lassen sich nicht durch eine Attrappe ersetzen; eine an den Konstruktor übergebene Instanz schon.
Häufig gestellte Fragen
Was bedeutet static in C#?
Ein static-Member gehört zum Typ selbst statt zu einem Objekt. Von einem statischen Feld gibt es genau eine Kopie, egal wie viele Objekte existieren, und eine statische Methode wird über den Typnamen aufgerufen (Math.Max(3, 7)), ohne eine Instanz zu erzeugen. Eine statische Methode hat kein this und kann daher Instanzfelder nicht direkt verwenden.
Was ist eine statische Klasse in C#?
Eine als static deklarierte Klasse kann nur statische Member enthalten und nie instanziiert werden (new darauf ist Fehler CS0712). Sie gruppiert zusammengehörige Funktionen, die keinen Objektzustand brauchen, wie Math, Console oder File. Erweiterungsmethoden müssen in einer statischen Klasse deklariert werden.
Wie behebe ich „An object reference is required for the non-static field, method, or property“?
Das ist Fehler CS0120: Eine statische Methode, oft Main, verwendet einen Instanzmember. Erzeuge entweder ein Objekt und rufe den Member darauf auf (var app = new Program(); app.Run();) oder markiere den Member als static, wenn er keine Daten pro Objekt braucht.
Was ist der Unterschied zwischen const und static readonly in C#?
Ein const ist eine Konstante zur Kompilierzeit (Zahlen, Strings, bool, Enums), deren Wert in jede Assembly kopiert wird, die ihn verwendet. Ein static readonly-Feld wird einmal zur Laufzeit zugewiesen, in seinem Initialisierer oder im statischen Konstruktor, und kann jeden Typ enthalten, etwa ein DateTime oder eine Liste. Nimm const für Werte, die sich nie ändern, und static readonly für alles andere.
Wann sollte ich in C# static verwenden?
Nimm static für Code, der nur mit seinen Parametern arbeitet (reine Hilfsmethoden wie ein Preisformatierer), für Konstanten und Caches, die wirklich global für das Programm sind, und für Fabrikmethoden. Vermeide static für alles, was Zustand pro Benutzer oder pro Anfrage hält oder was du in Tests austauschen willst: Geteilter veränderlicher Zustand ist schwer zu testen und ohne Locking nicht threadsicher.