closed (odwołanie w C#)

Począwszy od języka C# 15, można zastosować closed modyfikator do klasy w celu zadeklarowania zamkniętej hierarchii. Bezpośredni podtyp można uzyskać tylko z zamkniętej klasy w ramach deklarowanego zestawu. Ponieważ zestaw elementów potomnych bezpośrednich jest stały, switch wyrażenie obsługujące każdy bezpośredni element potomny wyczerpuje zamknięty typ podstawowy i nie wymaga domyślnego ramienia.

// Assembly 1
public closed record class JobStatus;
public record class Queued : JobStatus;
public record class Running(int PercentComplete) : JobStatus;
public record class Completed(TimeSpan Elapsed) : JobStatus;
public record class Failed(string Error) : JobStatus;

// Assembly 2
public record class Paused : JobStatus; // Error: 'JobStatus' is a closed class

Ograniczenie tego samego zestawu dotyczy tylko bezpośrednich elementów potomnych klasy zamkniętej. Klasa pochodząca z zamkniętej klasy nie jest zamknięta, chyba że oznaczysz ją closedrównież jako . Ponieważ Failed w poprzednim przykładzie jest to zwykły rekord, inny zestaw może pochodzić z niego:

// Assembly 2
public record class RetryableFailed(string Error, int Attempts) : Failed(Error); // OK: 'Failed' isn't sealed or closed

Jeśli chcesz również uniemożliwić wyprowadzanie Failed , zadeklaruj go jako sealed lub closed.

Dokumentacja języka C# zawiera ostatnio wydaną wersję języka C#. Zawiera również początkową dokumentację dla funkcjonalności w publicznych wersjach testowych nadchodzącego wydania języka.

Dokumentacja identyfikuje dowolną funkcję po raz pierwszy wprowadzoną w ostatnich trzech wersjach języka lub w bieżącej publicznej wersji zapoznawczej.

Tip

Aby dowiedzieć się, kiedy funkcja została po raz pierwszy wprowadzona w języku C#, zapoznaj się z artykułem dotyczącym historii wersji języka C#.

Note

closed jest kontekstowym słowem kluczowym. Ma specjalne znaczenie tylko wtedy, gdy pojawia się jako modyfikator w deklaracji klasy. Możesz nadal używać closed go jako identyfikatora w innych kontekstach. Jeśli musisz użyć closed jako identyfikatora w sytuacji, w której modyfikator będzie również prawidłowy, prefiks z @ (na przykład @closed), aby poinformować kompilator o traktowaniu go jako identyfikatora, a nie modyfikatora.

Reguły deklaracji

Modyfikator closed jest modyfikatorem klas:

  • Klasa closed jest niejawnie abstract. Nie można połączyć z closed modyfikatorem sealedjawnym static , abstractani jawnym.
  • Należy zadeklarować bezpośredni podtyp zamkniętej klasy w tym samym zestawie i module co zamknięta klasa bazowa.
  • Klasa pochodząca z zamkniętej klasy nie jest zamknięta. closed Ponownie zastosuj modyfikator, jeśli chcesz również zamknąć klasę pochodną.

Jeśli klasa ogólna pochodzi bezpośrednio z closed klasy, każdy parametr typu w klasie pochodnej musi być używany w specyfikacji klasy bazowej. Zamknięty skonstruowany typ jest typem ogólnym, którego argumenty typu są w pełni określone (na przykład ), w przeciwieństwie do typu otwartego, takiego jak Tree<T>Tree<int>. Typ otwarty może również zawierać określone argumenty typu, takie jak Dictionary<string, TValue>, gdzie TValue jest nadal parametrem typu. Aby zapoznać się z definicjami, zobacz Typy otwarte i zamknięte w specyfikacji języka. Ograniczenie pozwala kompilatorowi określić możliwe skonstruowane obiekty potomne dla danej konstrukcji bazowej. Konkretna konstrukcja bazowa nie może mieć odpowiedniej konstrukcji określonego potomka; reguła nie gwarantuje tej reguły.

public closed record class Tree<T>;

public record class Leaf<T>(T Value) : Tree<T>;                       // OK: 'T' appears in the base class
public record class Branch<T>(Tree<T> Left, Tree<T> Right) : Tree<T>; // OK: 'T' appears in the base class
public record class Constant<U>(U Value) : Tree<int> { } // Error: 'U' isn't used in the base class

Wyczerpujące wyrażenia przełącznika

switch Gdy wyrażenie obsługuje każdy bezpośredni element potomny zamkniętej klasy, kompilator uwzględnia przełącznik wyczerpujący i nie generuje ostrzeżenia o niewyczerpliwości:

public static string Describe(JobStatus status) => status switch
{
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: every direct descendant of 'JobStatus' is handled.
};

Gdy wyrażenie zarządzające przełącznikiem ma wartość null, null staje się kolejną możliwą wartością, którą przełącznik musi obsłużyć. Przełączenie JobStatus? jest wyczerpujące tylko wtedy, gdy obejmuje nullrównież :

public static string DescribeOrUnknown(JobStatus? status) => status switch
{
    null => "unknown",
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: every direct descendant of 'JobStatus' is handled, and null is handled.
};

Jeśli pominięto null ramię, kompilator ostrzega, że wzorzec null nie jest obsługiwany. Modyfikator closed dotyczy tylko klas, w tym klas rekordów.

Aby uzyskać więcej informacji na temat sposobu określania wyczerpującości przez kompilator, w tym sposobu interakcji zamkniętych hierarchii z ogólnymi ograniczeniami i ułatwieniami dostępu, zobacz Zamknięte wzorce hierarchii.

Parametry typu ograniczone do typu zamkniętego

Specyfikacja funkcji zamkniętych hierarchii traktuje parametr typu ograniczony do zamkniętej klasy tak samo jak klasa zamknięta w celu sprawdzania wyczerpującości. switch Wyrażenie, którego wartość rządząca ma taki parametr typu, jest wyczerpujące, gdy obsługuje każdy bezpośredni element potomny zamkniętego ograniczenia, niezależnie od tego, czy parametr typu pojawia się w metodzie, czy w typie zawierającym:

public static string DescribeJob<X>(X status) where X : JobStatus => status switch
{
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: 'X' is constrained to a closed type, so the compiler treats
    // this switch as exhaustive because every direct descendant is handled.
};

specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz Specyfikację funkcji Zamknięte hierarchie .

Zobacz także