"uso basado en patrones" y "declaraciones de uso"
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 y 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 especificaciones.
Problema planteado por experto: https://github.com/dotnet/csharplang/issues/114
Resumen
El lenguaje añadirá dos nuevas capacidades en torno a la instrucción using
con el fin de hacer más sencilla la gestión de recursos: using
debe reconocer un patrón desechable además de IDisposable
y añadir una declaración using
al lenguaje.
Motivación
La instrucción using
es una herramienta eficaz para la administración de recursos hoy en día, pero requiere un poco de ceremonia. Los métodos que tienen una serie de recursos para administrar se pueden enredar sintácticamente con una serie de instrucciones using
. Esta carga de sintaxis es tal que la mayoría de las directrices de estilo de codificación incluyen explícitamente una excepción respecto a los corchetes para este escenario.
La declaración using
elimina gran parte de la ceremonia aquí y pone a C# a la par con otros lenguajes que incluyen bloques de gestión de recursos. Además el using
basado en patrón permite a los desarrolladores ampliar el conjunto de tipos que pueden participar aquí. En muchos casos, se elimina la necesidad de crear tipos encapsuladores que solo existen para permitir el uso de valores en una instrucción using
.
Juntas estas características permiten a los desarrolladores simplificar y expandir los escenarios en los que se puede aplicar using
.
Diseño detallado
declaración using
El idioma permitirá agregar using
a una declaración de variable local. Esta declaración tendrá el mismo efecto que declarar la variable en una instrucción using
en la misma ubicación.
if (...)
{
using FileStream f = new FileStream(@"C:\source\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\source\using.md"))
{
// statements
}
}
La duración de una variable local using
se prolongará hasta el final del ámbito donde se declara. A continuación, las variables locales using
se eliminarán en el orden inverso en el que se declaran.
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("...");
using var f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
No existen restricciones en torno a goto
ni a ninguna otra construcción de flujo de control ante una declaración de using
. En su lugar, el código actúa igual que para la instrucción using
equivalente:
{
using var f1 = new FileStream("...");
target:
using var f2 = new FileStream("...");
if (someCondition)
{
// Causes f2 to be disposed but has no effect on f1
goto target;
}
}
Una variable local declarada en una declaración local de using
será implícitamente de solo lectura. Esto coincide con el comportamiento de las variables locales declaradas en una instrucción using
.
La gramática del idioma para las declaraciones de using
será la siguiente:
local-using-declaration:
'using' type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
Restricciones en torno a la declaración using
- Puede que no aparezca directamente dentro de una etiqueta de
case
, sino que debe estar dentro de un bloque dentro de la etiquetacase
. - Puede que no aparezca como parte de una declaración de variable de
out
. - Debe tener un inicializador para cada declarador.
- El tipo local debe convertirse implícitamente en
IDisposable
o cumplir el patrón deusing
.
uso basado en patrones
El lenguaje agregará la noción de un patrón descartable para tipos ref struct
: es decir, un ref struct
que disponga de un método de instancia accesible de Dispose
. Los tipos que se ajustan al patrón descartable pueden participar en una instrucción o declaración using
sin necesidad de implementar IDisposable
.
ref struct Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
Esto permitirá a los desarrolladores aprovechar using
para los tipos de ref struct
. Estos tipos no pueden implementar interfaces en C# 8 y, por tanto, no pueden participar en instrucciones using
.
Las mismas restricciones de una instrucción using
tradicional también se aplican aquí: las variables locales declaradas en el using
son de solo lectura, un valor de null
no hará que se produzca una excepción, etc. La generación de código solo será diferente en que no habrá una conversión a IDisposable
antes de llamar a Dispose:
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
Para ajustarse al patrón desechable, el método Dispose
debe ser un miembro de instancia accesible, sin parámetros y tener un tipo de retorno void
. No puede ser un método de extensión.
Consideraciones
Ninguna de estas consideraciones se implementó en C# 8
etiquetas de casos sin bloques
Un using declaration
es incorrecto directamente dentro de una etiqueta de case
debido a complicaciones en torno a su duración real. Una posible solución es simplemente darle la misma duración que un out var
en la misma ubicación. Se consideró que la complejidad adicional para la implementación de la funcionalidad y la facilidad para la solución alternativa (simplemente agregar un bloque a la etiqueta case
) no justificaban seguir este camino.
Expansiones futuras
variables locales fijas
Una instrucción fixed
tiene todas las propiedades de instrucciones using
que motivaron la capacidad de tener variables locales using
. Se debería considerar extender esta característica también a las variables locales fixed
. Las reglas de vida útil y ordenación deben aplicarse de igual manera para using
y fixed
aquí.
C# feature specifications