Dela via


Tillåt användning av aliasdirektiv för att referera till alla typer av typer

Not

Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.

Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader dokumenteras i de relevanta anteckningarna från Language Design Meeting (LDM) .

Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.

Championfråga: https://github.com/dotnet/csharplang/issues/8645

Sammanfattning

Slappna av using_alias_directive (§13.5.2) så att den kan peka på någon typ, inte bara namngivna typer. Detta stöder typer som inte tillåts i dag, till exempel tuppelns typer, pekartyper, matristyper osv. Detta skulle till exempel nu tillåtas:

using Point = (int x, int y);

Motivation

I evigheter har C# haft möjlighet att introducera alias för namnområden och namngivna typer (klasser, delegerade, gränssnitt, poster och structs). Detta fungerade acceptabelt bra eftersom det gav ett sätt att införa icke-motstridiga namn i fall där ett normalt namn som hämtades från using_directives kan vara tvetydigt, och det tillät ett sätt att ge ett enklare namn när man hanterar komplexa generiska typer. Ökningen av ytterligare komplexa typsymboler på språket har dock lett till mer användning där alias skulle vara värdefulla men för närvarande inte tillåts. Till exempel kan både tupplar och funktionspekare ofta ha stora och komplexa regelbundna textformer som kan vara jobbiga att skriva ner och svåra att läsa. Alias skulle hjälpa i dessa fall genom att ge ett kort namn som tillhandahålls av utvecklare och som sedan kan användas i stället för de fullständiga strukturella formulären.

Detaljerad design

Vi kommer att ändra grammatiken i using_alias_directive på så sätt:

using_alias_directive
-    : 'using' identifier '=' namespace_or_type_name ';'
+    : 'using' identifier '=' (namespace_name | type) ';'
    ;

Ogiltighetskommentarer för toppnivåreferenstypen tillåts inte.

Intressant nog behöver det mesta av specifikationsspråket i §13.5.2 inte ändras. De flesta språk i det refererar redan till "namnområde eller typ", till exempel:

Using_alias_directive inför en identifierare som fungerar som ett alias för ett namnområde eller en typ i den omedelbart omslutande kompileringsenheten eller namnområdeskroppen.

Detta är fortfarande sant, bara att grammatiken nu tillåter att "typen" är valfri godtycklig typ, inte den begränsade uppsättning som tillåts av namespace_or_type_name tidigare.

De avsnitt som behöver uppdateras är:

- The order in which using_alias_directives are written has no significance, and resolution of the namespace_or_type_name referenced by a using_alias_directive is not affected by the using_alias_directive itself or by other using_directives in the immediately containing compilation unit or namespace body. In other words, the namespace_or_type_name of a using_alias_directive is resolved as if the immediately containing compilation unit or namespace body had no using_directives. A using_alias_directive may however be affected by extern_alias_directives in the immediately containing compilation unit or namespace body. In the example
+ The order in which using_alias_directives are written has no significance, and resolution of the `(namespace_name | type)` referenced by a using_alias_directive is not affected by the using_alias_directive itself or by other using_directives in the immediately containing compilation unit or namespace body. In other words, the `(namespace_name | type)` of a using_alias_directive is resolved as if the immediately containing compilation unit or namespace body had no using_directives. A using_alias_directive may however be affected by extern_alias_directives in the immediately containing compilation unit or namespace body. In the example
- The namespace_name referenced by a using_namespace_directive is resolved in the same way as the namespace_or_type_name referenced by a using_alias_directive. Thus, using_namespace_directives in the same compilation unit or namespace body do not affect each other and can be written in any order.
+ The namespace_name referenced by a using_namespace_directive is resolved in the same way as the namespace_or_type_name referenced by a using_alias_directive. Thus, using_namespace_directives in the same compilation unit or namespace body do not affect each other and can be written in any order.
+ It is illegal for a using alias type to be a nullable reference type.

    1. `using X = string?;` is not legal.
    2. `using X = List<string?>;` is legal.  The alias is to `List<...>` which is itself not a nullable reference type itself, even though it contains one as a type argument.
    3. `using X = int?;` is legal.  This is a nullable *value* type, not a nullable *reference* type.

Stöd för alias för typer som innehåller pekare.

En ny osäker kontext läggs till via ett valfritt "osäkert" nyckelord i using_alias_directive produktion:

using_alias_directive
+    : 'using' 'unsafe'? identifier '=' (namespace_name | type) ';'
    ;
    
using_static_directive
+    : 'using' 'static' 'unsafe'? type_name ';'
    ;

+ 'unsafe' can only be used with an using_alias_directive or using_static_directive, not a using_directive.
+ The 'unsafe' keyword present in a 'using_alias_directive' causes the entire textual extent of the 'type' portion (not the 'namespace_name' portion) to become an unsafe context. 
+ The 'unsafe' keyword present in a 'using_static_directive' causes the entire textual extent of the 'type_name' portion to become an unsafe context.