Menu

static w C#: klasy, metody, pola i konstruktory statyczne

Co oznacza static w C#: składowe należące do typu, a nie do obiektu, stan współdzielony przez instancje, metody i klasy statyczne, konstruktory statyczne, const a static readonly, using static i błąd CS0120.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

static oznacza składową, która należy do typu, a nie do obiektu. Pole instancji istnieje raz na obiekt; pole statyczne istnieje raz i kropka. Metoda instancyjna działa na obiekcie (order.Ship()); metoda statyczna działa na typie (Math.Round(x)) i w ogóle nie potrzebuje obiektu.

Pola statyczne: jedna kopia, współdzielona

Najprościej zobaczyć różnicę na liczniku. Każde Order ma własne Id, ale liczba dotąd utworzonych zamówień musi być przechowywana w jakimś wspólnym miejscu.

Wynik:

Ana #1, Ben #2, Chen #3
Orders created: 3

Do składowych statycznych odwołuje się przez nazwę typu: Order.Created, a nie a.Created. C# nie pozwala sięgać do składowej statycznej przez instancję (błąd CS0176), dzięki czemu w miejscu wywołania od razu widać, że wartość jest współdzielona.

Metody statyczne

Metoda statyczna nie ma this. Pracuje tylko ze swoimi parametrami i innymi składowymi statycznymi. Dlatego to naturalny kształt dla funkcji pomocniczych, które obliczają coś z danych wejściowych:

Wynik:

61.38 EUR
7

Samo Main jest statyczne: środowisko uruchomieniowe wywołuje je, zanim powstanie jakikolwiek obiekt.

Błąd CS0120: kod statyczny używa składowych instancji

Ponieważ Main jest statyczne, początkujący często trafiają na ten błąd, gdy tylko dodadzą drugą metodę:

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

Metoda statyczna nie ma obiektu, więc nie ma dla niej żadnego visits do zwiększenia. Są dwa rozwiązania, a właściwe zależy od tego, czym jest składowa:

  • Składowa to naprawdę dane konkretnego obiektu: utwórz obiekt i użyj go. var app = new Program(); app.Greet();
  • Składowa nie potrzebuje stanu obiektu: oznacz ją jako static. static void Greet() { ... }

Oznaczanie wszystkiego jako static, żeby błąd zniknął, działa w malutkim programie, a w prawdziwym zamienia się w stan globalny. Zdecyduj, pytając, czy dane należą do jednego obiektu, czy do całego programu.

W drugą stronę zawsze wolno: metody instancyjne mogą swobodnie wywoływać składowe statyczne.

Klasy statyczne

Klasa zadeklarowana jako static może zawierać tylko składowe statyczne i nigdy nie można utworzyć jej instancji. To nazwana grupa funkcji i stałych.

Wynik:

77
100
True

Kompilator pilnuje tej umowy: składowa instancji w klasie statycznej to błąd CS0708, a new na niej to błąd CS0712. Math, Console, File, Path i Enumerable to klasy statyczne. Metody rozszerzające również muszą znajdować się w klasie statycznej.

Konstruktory statyczne i static readonly

Pole statyczne, którego wartość wymaga więcej niż jednego wyrażenia, można ustawić w konstruktorze statycznym, który środowisko uruchomieniowe wykonuje raz, przed pierwszym użyciem typu:

Wynik:

Before first use
ShippingRates initialized
5.50
3
2026-01-01

readonly oznacza, że pole można przypisać tylko w jego inicjalizatorze albo w konstruktorze statycznym. Potem nie da się go ponownie przypisać, choć obiekt, na który wskazuje, nadal może być modyfikowalny, i dlatego słownik jest udostępniony jako IReadOnlyDictionary.

const a static readonly

Oba dają nazwaną wartość współdzieloną przez cały program, a różnią się tym, kiedy wartość zostaje ustalona:

conststatic readonly
Wartość ustalanaw czasie kompilacjiw czasie działania, raz
Dozwolone typyliczby, char, bool, string, enumy, nulldowolny typ
Niejawnie statycznetak (nie można napisać static const)statyczne deklarowane jawnie
Kopiowane do wywołujących assemblytaknie, odczytywane z pola
Użycie w przypadkach switch i argumentach atrybutówtaknie

Wiersz o kopiowaniu ma znaczenie dla bibliotek: jeśli assembly A deklaruje public const int MaxItems = 50;, a assembly B go używa, B zawiera literał 50. Zmiana w A na 100 nic nie daje w B, dopóki B nie zostanie ponownie skompilowane. Dla wartości, które mogą się zmieniać między wersjami, wybieraj static readonly.

using static

Dyrektywa using static (C# 6) importuje statyczne składowe typu, więc możesz je wywoływać bez nazwy typu:

Wynik:

Area: 28.27
40

Dobrze się to czyta w kodzie pełnym obliczeń matematycznych. Gdzie indziej używaj tego oszczędnie: samo WriteLine albo Parse ukrywa, z którego typu pochodzi metoda.

Stan statyczny i wątki

Pole statyczne jest współdzielone przez każdy wątek w procesie. Zwiększanie go jednocześnie z kilku wątków gubi aktualizacje, bo created++ to odczyt, dodawanie i zapis, a dwa wątki mogą je przeplatać. Do liczników używaj Interlocked.Increment(ref created), a do czegokolwiek większego lock. Najczęściej daje to o sobie znać w aplikacjach webowych: każde żądanie działa na jakimś wątku, więc pole statyczne przechowujące "bieżącego użytkownika" jest wspólne dla wszystkich użytkowników.

Jeszcze jeden niuans: w klasie generycznej każdy skonstruowany typ dostaje własne pola statyczne. Cache<int>.Count i Cache<string>.Count to dwa różne pola.

Kiedy używać static

Dobre zastosowania:

  • Czyste funkcje pomocnicze, które obliczają wynik ze swoich argumentów: formatowanie, konwersje, walidacja.
  • Stałe i dane wyszukiwania tylko do odczytu współdzielone przez program.
  • Metody fabrykujące, takie jak TimeSpan.FromMinutes(5) albo twoje własne Temperature.FromCelsius(21).
  • Metody rozszerzające.

Złe zastosowania:

  • Modyfikowalny stan globalny (bieżący użytkownik, koszyk, zmieniające się ustawienia). Wiąże ze sobą każdy fragment kodu, który go dotyka, i uzależnia testy od pozostałości po innych testach.
  • Wszystko, co zechcesz podmienić w testach, na przykład zegar, bazę danych albo nadawcę e-maili. Wywołań statycznych nie da się zastąpić atrapą; instancję przekazaną do konstruktora da się.

Najczęściej zadawane pytania

Co oznacza static w C#?

Składowa static należy do samego typu, a nie do żadnego obiektu. Pole statyczne istnieje w jednej kopii bez względu na to, ile jest obiektów, a metodę statyczną wywołuje się na nazwie typu (Math.Max(3, 7)) bez tworzenia instancji. Metoda statyczna nie ma this, więc nie może bezpośrednio używać pól instancji.

Czym jest klasa statyczna w C#?

Klasa zadeklarowana jako static może zawierać tylko składowe statyczne i nigdy nie można utworzyć jej instancji (new na niej to błąd CS0712). Grupuje powiązane funkcje, które nie potrzebują stanu obiektu, jak Math, Console czy File. Metody rozszerzające muszą być zadeklarowane w klasie statycznej.

Jak naprawić błąd "An object reference is required for the non-static field, method, or property"?

To błąd CS0120: metoda statyczna, często Main, używa składowej instancji. Albo utwórz obiekt i wywołaj składową na nim (var app = new Program(); app.Run();), albo oznacz składową jako static, jeśli nie potrzebuje danych konkretnego obiektu.

Jaka jest różnica między const a static readonly w C#?

const to stała czasu kompilacji (liczby, stringi, bool, enumy), której wartość jest kopiowana do każdego assembly, które jej używa. Pole static readonly jest przypisywane raz w czasie działania, w inicjalizatorze albo w konstruktorze statycznym, i może przechowywać dowolny typ, na przykład DateTime albo listę. Używaj const dla wartości, które nigdy się nie zmienią, a static readonly dla wszystkiego innego.

Kiedy używać static w C#?

Używaj static dla kodu, który działa tylko na swoich parametrach (czyste funkcje pomocnicze, na przykład formatowanie ceny), dla stałych i cache naprawdę globalnych dla programu oraz dla metod fabrykujących. Unikaj static dla wszystkiego, co przechowuje stan konkretnego użytkownika lub żądania albo co zechcesz podmienić w testach: współdzielony modyfikowalny stan trudno testować i bez blokad nie jest bezpieczny między wątkami.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ