Compartilhar via


Permitir que o uso da diretiva de alias faça referência a qualquer tipo de Tipo

Nota

Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele inclui alterações de especificação propostas, juntamente com as informações necessárias durante o design e o desenvolvimento do recurso. Esses artigos são publicados até que as alterações de especificação propostas sejam finalizadas e incorporadas na especificação ECMA atual.

Pode haver algumas discrepâncias entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da reunião de design de idioma (LDM).

Você pode saber mais sobre o processo de adoção de speclets de recursos no padrão de linguagem C# no artigo sobre as especificações de .

Problema do especialista: https://github.com/dotnet/csharplang/issues/8645

Resumo

Flexibilize a using_alias_directive (§13.5.2) para que ela possa apontar para qualquer tipo, não apenas para os tipos nomeados. Isso ofereceria suporte a tipos não permitidos hoje, como: tipos de tupla, tipos de ponteiro, tipos de matriz etc. Por exemplo, isso agora seria permitido:

using Point = (int x, int y);

Motivação

Há muito tempo, o C# tem a capacidade de introduzir aliases para namespaces e tipos nomeados (classes, delegates, interfaces, registros e structs). Isso funcionou de forma aceitável, pois forneceu um meio de introduzir nomes não conflitantes em casos em que um nome normal extraído de using_directivepode ser ambíguo, e permitiu uma maneira de fornecer um nome mais simples ao lidar com tipos genéricos complexos. No entanto, o aumento de símbolos de tipo complexo adicionais na linguagem fez com que mais uso surgisse onde os aliases seriam valiosos, mas atualmente não são permitidos. Por exemplo, as tuplas e os ponteiros de função muitas vezes podem possuir formas textuais regulares grandes e complexas que podem ser difíceis de escrever continuamente e pesadas de ler. Os aliases ajudariam nesses casos, dando um nome curto, fornecido pelo desenvolvedor, que pode ser usado no lugar dessas formas estruturais completas.

Design detalhado

Mudaremos a gramática de using_alias_directive assim:

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

As anotações de nulidade de tipo de referência de nível superior não são permitidas.

Curiosamente, a maior parte da linguagem de especificação em §13.5.2 não precisa ser alterada. A maioria dos idiomas nele já se refere a "namespace ou tipo", por exemplo:

Uma using_alias_directive apresenta um identificador que serve como um alias para um namespace ou tipo dentro da unidade de compilação ou do corpo do namespace imediatamente envolvente.

Isso permanece verdadeiro, apenas que a gramática agora permite que o "tipo" seja qualquer tipo arbitrário, não o conjunto limitado permitido por namespace_or_type_name anteriormente.

As seções que precisam ser atualizadas são:

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

Suporte a aliases para tipos que contêm ponteiros.

Um novo contexto não seguro é adicionado por meio de uma palavra-chave opcional "não seguro" na produção da 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.