Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
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
closedjest niejawnieabstract. Nie można połączyć zclosedmodyfikatoremsealedjawnymabstract,staticani 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.
closedPonownie 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. Ta reguła nie closed dotyczy samego modyfikatora: zamknięty typ skonstruowany 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>. Reguła zapewnia, że każdy zamknięty skonstruowany typ klasy bazowej ma dokładnie jeden odpowiedni zamknięty typ skonstruowany wśród jego bezpośrednich elementów potomnych, więc kompilator może wnioskować o wyczerpującości.
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. Ta sama reguła ma zastosowanie, czy zamknięty typ jest klasą, czy strukturą podniesioną do typu dopuszczalnego wartości null.
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
Parametr typu ograniczony do zamkniętej klasy jest traktowany jako zamknięta klasa do sprawdzania wyczerpującości. Wyrażenie switch , 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:
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 its direct descendants exhaust the switch.
};
Ta reguła ma zastosowanie, czy parametr typu pojawia się w metodzie, czy w typie zawierającym.
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz Specyfikację funkcji Zamknięte hierarchie .