Expressões new
com tipo de destino
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/100
Resumo
Não exija especificação de tipo para construtores quando o tipo for conhecido.
Motivação
Permitir inicialização de campo sem duplicar o tipo.
Dictionary<string, List<int>> field = new() {
{ "item1", new() { 1, 2, 3 } }
};
Permitir omitir o tipo quando ele puder ser inferido do uso.
XmlReader.Create(reader, new() { IgnoreWhitespace = true });
Instancie um objeto sem especificar o tipo.
private readonly static object s_syncObj = new();
Especificação
Um novo formato sintático, target_typed_new da object_creation_expression é aceito no qual o tipo é opcional.
object_creation_expression
: 'new' type '(' argument_list? ')' object_or_collection_initializer?
| 'new' type object_or_collection_initializer
| target_typed_new
;
target_typed_new
: 'new' '(' argument_list? ')' object_or_collection_initializer?
;
Uma expressão target_typed_new não tem um tipo. No entanto, há uma nova conversão de criação de objeto que é uma conversão implícita de expressão, que existe de um target_typed_new para cada tipo.
Dado um tipo alvo T
, o tipo T0
é o tipo subjacente de T
se T
for uma instância de System.Nullable
. Caso contrário, T0
será T
. O significado de uma expressão target_typed_new que é convertida no tipo T
é o mesmo que o significado de um object_creation_expression correspondente que especifica T0
como o tipo.
Será um erro em tempo de compilação se um target_typed_new for usado como um operando de um operador unário ou binário, ou se for utilizado em contextos nos quais não está sujeito a uma conversão de criação de objeto .
Problema Aberto: deveríamos permitir delegados e tuplas como tipo de destino?
As regras acima incluem delegados (um tipo de referência) e tuplas (um tipo de struct). Embora ambos os tipos sejam construíveis, se o tipo for inferível, uma função anônima ou um literal de tupla já poderá ser usado.
(int a, int b) t = new(1, 2); // "new" is redundant
Action a = new(() => {}); // "new" is redundant
(int a, int b) t = new(); // OK; same as (0, 0)
Action a = new(); // no constructor found
Variado
Veja a seguir as consequências da especificação:
-
throw new()
é permitido (o tipo de destino éSystem.Exception
) - O tipo de destino
new
não é permitido com operadores binários. - Não é permitido quando não há tipo para ser direcionado: operadores unários, coleção de uma
foreach
, em umusing
, em desconstrução, em uma expressãoawait
, como uma propriedade de tipo anônimo (new { Prop = new() }
), em uma instruçãolock
, em umsizeof
, em uma instruçãofixed
, em acesso de membro (new().field
), em uma operação dinamicamente despachada (someDynamic.Method(new())
), em uma consulta LINQ, como o operando do operadoris
, como o operando esquerdo do operador??
, ... - Também é proibido como um
ref
. - Os tipos a seguir não são permitidos como destinos da conversão
- tipos de enumeração:
new()
funcionará (comonew Enum()
funciona para fornecer o valor padrão), masnew(1)
não funcionará, pois os tipos de enumeração não têm um construtor. - Tipos de interface: isso funcionaria da mesma forma que a expressão de criação correspondente para tipos COM.
- Tipos de matriz: matrizes precisam de uma sintaxe especial para fornecer o comprimento.
- dinâmico: não permitimos
new dynamic()
, portanto, não permitimosnew()
comdynamic
como um tipo de destino. - tuplas: elas têm o mesmo significado que a criação de um objeto usando o tipo subjacente.
- Todos os outros tipos que não são permitidos na expressão de criação de objetos também são excluídos, como, por exemplo, tipos ponteiros.
- tipos de enumeração:
Inconvenientes
Houve algumas preocupações com o tipo de destino new
a criação de novas categorias de alterações interruptivas, mas já temos isso com null
e default
, e isso não tem sido um problema significativo.
Alternativas
A maioria das reclamações sobre os tipos serem muito longos para duplicação na inicialização de campos refere-se aos argumentos do tipo , não ao tipo em si. Poderíamos inferir apenas os argumentos do tipo, como new Dictionary(...)
(ou similar), e inferir argumentos do tipo localmente a partir dos argumentos ou do inicializador da coleção.
Perguntas
- Devemos proibir o uso em árvores de expressão? (não)
- Como a funcionalidade interage com argumentos
dynamic
? (sem tratamento especial) - Como o IntelliSense deve trabalhar com
new()
? (somente quando houver um único tipo de destino)
Reuniões de Design
C# feature specifications