Expressões de new
tipo de destino
Observação
Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele inclui mudanças de especificação propostas, juntamente com as informações necessárias durante o design e desenvolvimento do recurso. Estes artigos são publicados até que as alterações de especificações 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 Language Design Meeting (LDM).
Você pode saber mais sobre o processo de adoção de especificações de recursos no padrão de linguagem C# no artigo sobre as especificações .
Questão campeã: https://github.com/dotnet/csharplang/issues/100
Resumo
Não requer especificação de tipo para construtores quando o tipo é conhecido.
Motivação
Permitir a inicialização do campo sem duplicar o tipo.
Dictionary<string, List<int>> field = new() {
{ "item1", new() { 1, 2, 3 } }
};
Permitir omitir o tipo quando ele pode ser inferido a partir do uso.
XmlReader.Create(reader, new() { IgnoreWhitespace = true });
Instanciar um objeto sem especificar o tipo.
private readonly static object s_syncObj = new();
Especificação
Aceita-se uma nova forma sintática, target_typed_new do object_creation_expression, na 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 a partir de expressão, que existe de um target_typed_new para qualquer 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
é T
. O significado de uma expressão target_typed_new que é convertida para o tipo T
é o mesmo que o significado de um object_creation_expression correspondente que especifica T0
como o tipo.
É 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 usado onde não está sujeito a uma conversão de criação de objeto.
Questão em aberto: devemos permitir delegados e tuplas como o tipo alvo?
As regras acima incluem delegados (um tipo de referência) e tuplas (um tipo de estrutura). Embora ambos os tipos sejam construíveis, se o tipo for inferível, uma função anônima ou um literal de tupla já podem ser usados.
(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
Diversos
As consequências da especificação são as seguintes:
-
throw new()
é permitido (o tipo de destino éSystem.Exception
) - Tipos-alvo
new
não são permitidos com operadores binários. - Não é permitido quando não há tipo a ser visado: operadores unários, coleta de um
foreach
, em umausing
, em uma 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 um acesso de membro (new().field
), em uma operação despachada dinamicamente (someDynamic.Method(new())
), em uma consulta LINQ, como o operando do operadoris
, como o operando esquerdo do operador??
, ... - Também não é permitido como
ref
. - Os seguintes tipos de tipos não são permitidos como alvos da conversão
-
Tipos de Enum:
new()
funcionará (tal comonew Enum()
funciona para dar o valor padrão), masnew(1)
não funcionará, pois os tipos de enum não têm 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âmica: não permitimos
new dynamic()
, por isso não permitimosnew()
comdynamic
como tipo de destino. - tuplas: Estes têm o mesmo significado que uma criação de objeto usando o tipo subjacente.
- Todos os outros tipos que não são permitidos na expressão de criação de objeto também são excluídos, por exemplo, tipos de ponteiro.
-
Tipos de Enum:
Desvantagens
Havia algumas preocupações com new
de tipo alvo criando novas categorias de mudanças de rutura, mas já temos isso com null
e default
, e isso não tem sido um problema significativo.
Alternativas
A maioria das reclamações de que os tipos são demasiado longos para duplicar na inicialização de campo refere-se apenas aos argumentos de tipo como e não ao tipo em si. No entanto, podemos optar por inferir apenas os argumentos de tipo como new Dictionary(...)
(ou similar) e inferir argumentos de tipo localmente a partir dos argumentos ou a partir do inicializador de coleção.
Perguntas
- Devemos proibir utilizações em árvores de expressões? (não)
- Como é que a funcionalidade interage com os argumentos
dynamic
? (sem tratamento especial) - Como o IntelliSense deve funcionar com
new()
? (apenas quando existe um único tipo de destino)
Reuniões de design
C# feature specifications