Expresiones new
con tipo de destino
Nota
Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos e se incorporan en la especificación ECMA actual.
Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.
Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C# en el artículo sobre las especificaciones de .
Problema planteado por el experto: https://github.com/dotnet/csharplang/issues/100
Resumen
No requiera especificación de tipo para constructores cuando se conoce el tipo.
Motivación
Permitir la inicialización de campos sin duplicar el tipo.
Dictionary<string, List<int>> field = new() {
{ "item1", new() { 1, 2, 3 } }
};
Permitir omitir el tipo cuando se puede deducir del uso.
XmlReader.Create(reader, new() { IgnoreWhitespace = true });
Instanciar un objeto sin deletrear el tipo.
private readonly static object s_syncObj = new();
Especificación
Se acepta una nueva forma sintáctica, target_typed_new de la object_creation_expression en la que el tipo de es 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?
;
Una expresión target_typed_new no tiene un tipo. Sin embargo, hay una nueva conversión de creación de objeto que es una conversión implícita de expresión, que existe de un target_typed_new a cada tipo.
Dado un tipo de destino T
, el tipo subyacente de T
es el tipo T0
si T
es una instancia de System.Nullable
. De lo contrario, T0
es T
. El significado de una expresión de target_typed_new que se convierte en el tipo T
es el mismo que el significado de un object_creation_expression correspondiente que especifica T0
como tipo.
Es un error en tiempo de compilación si un target_typed_new se utiliza como operando de un operador unario o binario, o si se utiliza donde no está sujeto a una conversión de creación de objeto.
Cuestión abierta: ¿deberíamos permitir delegados y tuplas como tipo de destino?
Las reglas anteriores incluyen delegados (un tipo de referencia) y tuplas (un tipo struct). Aunque ambos tipos son construibles, si el tipo es inferible, ya se puede utilizar una función anónima o un literal de tupla.
(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
Misceláneo
A continuación se muestran las consecuencias de la especificación:
- Se permite
throw new()
(el tipo de destino esSystem.Exception
) - El tipo objetivo
new
no está permitido con operadores binarios. - No está permitido cuando no hay un tipo al que apuntar: operadores unarios, colección de un
foreach
, en unusing
, en una deconstrucción, en una expresiónawait
, como una propiedad de tipo anónimo (new { Prop = new() }
), en una instrucciónlock
, en unsizeof
, en una instrucciónfixed
, en un acceso a miembro (new().field
), en una operación despachada dinámicamente (someDynamic.Method(new())
), en una consulta LINQ, como operando del operadoris
, como operando izquierdo del operador??
, etc. - Tampoco está permitido como
ref
. - No se permiten los siguientes tipos de tipos como destinos de la conversión.
- tipos de enumeración:
new()
funcionará (ya quenew Enum()
funciona para proporcionar el valor predeterminado), peronew(1)
no funcionará porque los tipos de enumeración no tienen constructor. - Tipos de interfaz: Esto funcionaría igual que la expresión de creación correspondiente para los tipos COM.
- Tipos de matriz: matrices necesitan una sintaxis especial para proporcionar la longitud.
- dinámico: no permitimos
new dynamic()
, por lo que no permitimosnew()
condynamic
como tipo destino. - tuplas: Estas tienen el mismo significado que la creación de un objeto utilizando el tipo subyacente.
- En el object_creation_expression se excluyen también todos los demás tipos que no están permitidos, como, por ejemplo, los tipos de puntero.
- tipos de enumeración:
Inconvenientes
Hubo algunas preocupaciones con tipo-objetivo new
creando nuevas categorías de cambios de ruptura, pero ya tenemos que con null
y default
, y que no ha sido un problema significativo.
Alternativas
La mayoría de las quejas sobre los tipos de ser demasiado largo para duplicar en la inicialización de campo es sobre argumentos de tipo no el tipo en sí, podríamos inferir solo tipo argumentos como new Dictionary(...)
(o similar) e inferir tipo argumentos localmente de argumentos o el inicializador de colección.
Preguntas
- ¿Deberíamos prohibir los usos en árboles de expresión? (no)
- ¿Cómo interactúa la característica con los argumentos
dynamic
? (sin tratamiento especial) - ¿Cómo debe funcionar IntelliSense con
new()
? (Solo cuando hay un único tipo de destino).
Reuniones de diseño
C# feature specifications