Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Från och med C# 15 kan du tillämpa closed modifieraren på en klass för att deklarera en stängd hierarki. Du kan bara härleda en direkt undertyp från en sluten klass i den deklarerande sammansättningen. Eftersom uppsättningen med direkta underordnade objekt är fast, uttömmer ett switch uttryck som hanterar varje direkt underordnade den stängda bastypen och behöver ingen standardarm.
// 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
Begränsningen för samma sammansättning gäller endast för direkta underordnade till den stängda klassen. En klass som härleds från en stängd klass är inte i sig stängd om du inte också markerar den closed. Eftersom Failed i föregående exempel är en vanlig post kan en annan sammansättning härledas från den:
// Assembly 2
public record class RetryableFailed(string Error, int Attempts) : Failed(Error); // OK: 'Failed' isn't sealed or closed
Om du också vill förhindra härledning Failed deklarerar du det som sealed eller closed.
C#-språkreferensen dokumenterar den senaste versionen av C#-språket. Den innehåller även inledande dokumentation för funktioner i offentliga förhandsversioner för den kommande språkversionen.
Dokumentationen identifierar alla funktioner som först introducerades i de tre senaste versionerna av språket eller i aktuella offentliga förhandsversioner.
Tip
Information om när en funktion först introducerades i C# finns i artikeln om språkversionshistoriken för C#.
Note
closed är ett kontextuellt nyckelord. Den har en särskild betydelse endast när den visas som en modifierare i en klassdeklaration. Du kan fortsätta att använda closed som identifierare i andra sammanhang. Om du behöver använda closed som identifierare i en position där modifieraren också skulle vara giltig, prefixar du den med @ (till exempel @closed) för att be kompilatorn att behandla den som en identifierare i stället för modifieraren.
Deklarationsregler
Modifieraren closed är en klassmodifierare:
- En
closedklass är implicitabstract. Du kan inte kombineraclosedmedsealed,staticeller en explicitabstractmodifierare. - Du måste deklarera en direkt undertyp av en sluten klass i samma sammansättning och modul som den stängda basklassen.
- En klass som härleds från en stängd klass stängs inte själv.
closedTillämpa modifieraren igen om du vill att en härledd klass också ska stängas.
Om en generisk klass direkt härleds från en closed klass måste varje typparameter i den härledda klassen användas i basklassspecifikationen. Den här regeln handlar inte om själva modifieraren: en sluten closedkonstruktionstyp är en allmän typ vars typargument är helt angivna (till exempel Tree<int>), i stället för en öppen typ som Tree<T>. Regeln ser till att varje sluten konstruerad typ av basklass har exakt en motsvarande sluten konstruerad typ bland sina direkta underordnade, så kompilatorn kan resonera om fullständighet.
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
Uttömmande växeluttryck
När ett switch uttryck hanterar varje direkt underordnad till en sluten klass anser kompilatorn att växeln är fullständig och genererar ingen icke-fullständighetsvarning:
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.
};
När växelns styrande uttryck är null blir null ett annat möjligt värde som växeln måste hantera. En växling JobStatus? är endast fullständig när den även omfattar null:
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.
};
Om du utelämnar null armen varnar kompilatorn för att mönstret null inte hanteras. Samma regel gäller om den stängda typen är en klass eller en struct som lyfts till en nullbar typ.
Mer information om hur kompilatorn avgör fullständighet, inklusive hur stängda hierarkier interagerar med allmänna begränsningar och tillgänglighet, finns i Stängda hierarkimönster.
Typparametrar som är begränsade till en sluten typ
En typparameter som är begränsad till en sluten klass behandlas som den stängda klassen för fullständighetskontroller. Ett switch uttryck vars styrande värde har en sådan typparameter är uttömmande när det hanterar varje direkt underordnad till den stängda begränsningen:
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.
};
Den här regeln gäller om typparametern visas på en metod eller på den innehållande typen.
Språkspecifikation för C#
Mer information finns i funktionsspecifikationen För stängda hierarkier .