Udostępnij za pośrednictwem


Zezwalaj na używanie dyrektywy aliasu w celu odwołowania się do dowolnego rodzaju typu

Notatka

Ten artykuł jest specyfikacją funkcji. Specyfikacja służy jako dokument projektowy dla funkcji. Zawiera proponowane zmiany specyfikacji wraz z informacjami wymaganymi podczas projektowania i opracowywania funkcji. Te artykuły są publikowane do momentu sfinalizowania proponowanych zmian specyfikacji i włączenia ich do obecnej specyfikacji ECMA.

Mogą wystąpić pewne rozbieżności między specyfikacją funkcji a ukończoną implementacją. Te różnice są odnotowane w odpowiednich notatkach ze spotkań projektowych dotyczących języka (LDM) .

Więcej informacji na temat procesu wdrażania specyfikacji funkcji można znaleźć w standardzie języka C# w artykule dotyczącym specyfikacji .

Problem z mistrzem: https://github.com/dotnet/csharplang/issues/8645

Streszczenie

Rozluźnij dyrektywę using_alias (§13.5.2), aby umożliwić jej wskazywanie na dowolny rodzaj typu, a nie tylko typy nazwane. Obsługiwałoby to typy niedozwolone dzisiaj, jak: krotki, typy wskaźnikowe, typy tablic itp. Na przykład, byłoby to teraz dozwolone:

using Point = (int x, int y);

Motywacja

Od dawna, C# ma możliwość wprowadzania aliasów dla przestrzeni nazw i nazwanych typów (klas, delegacji, interfejsów, rekordów i struktur). To działało zadowalająco dobrze, ponieważ stanowiło sposób wprowadzenia nazw niepowodujących konfliktów w przypadkach, gdy zwykle używana nazwa pobierana z using_directives może być niejednoznaczna, i umożliwiło nadanie prostszej nazwy podczas radzenia sobie ze złożonymi typami ogólnymi. Jednak wzrost dodatkowych, bardziej złożonych symboli typu w języku spowodował pojawienie się więcej sytuacji, gdzie aliasy byłyby cenne, ale obecnie nie są dozwolone. Na przykład zarówno krotki, jak i wskaźniki funkcji często mogą mieć duże i złożone regularne formy tekstowe, których ciągłe zapisywanie może być uciążliwe, oraz trudne do czytania. Aliasy pomogłyby w tych przypadkach, podając krótką, podaną przez deweloperów nazwę, która może być następnie używana zamiast tych pełnych form strukturalnych.

Szczegółowy projekt

W ten sposób zmienimy gramatykę using_alias_directive:

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

Adnotacje na temat nullowalności typu odwołania najwyższego poziomu są niedozwolone.

Co ciekawe, większość języka specyfikacji w §13.5.2 nie musi się zmieniać. Większość języka w nim odwołuje się już do "przestrzeni nazw lub typu", na przykład:

Using_alias_directive wprowadza identyfikator, który służy jako alias dla przestrzeni nazw lub typu w obrębie natychmiast otaczającej jednostki kompilacji lub treści przestrzeni nazw.

Pozostaje to prawdą, z tym że gramatyka teraz pozwala, aby "typ" był dowolnym typem, a nie ograniczonym zestawem dozwolonym wcześniej przez namespace_or_type_name.

Sekcje, które wymagają aktualizacji, to:

- 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.

Obsługa aliasów dla typów zawierających wskaźniki.

Nowy niebezpieczny kontekst jest dodawany za pomocą opcjonalnego słowa kluczowego "niebezpieczne" w środowisku produkcyjnym using_alias_directive:

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.