"utilização baseada em padrões" e "utilização de declarações"
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/114
Resumo
A linguagem adicionará dois novos recursos em torno da instrução using
para tornar o gerenciamento de recursos mais simples: using
deve reconhecer um padrão descartável além de IDisposable
e adicionar uma declaração using
ao idioma.
Motivação
A declaração using
é uma ferramenta eficaz para a gestão de recursos hoje, mas requer um pouco de cerimônia. Métodos que têm uma série de recursos para gerenciar podem ficar sintaticamente atolados com uma série de using
declarações. Esta carga de sintaxe é tal que a maioria dos guias de estilo de codificação explicitamente tem uma exceção em relação ao uso de chavetas para este cenário.
A declaração using
remove grande parte da cerimônia aqui e coloca o C# no mesmo nível de outras linguagens que incluem blocos de gerenciamento de recursos. Além disso, a using
baseada em padrões permite que os desenvolvedores expandam o conjunto de tipos que podem participar aqui. Em muitos casos, elimina-se a necessidade de criar tipos de embalamento que só existem para permitir o uso de valores numa instrução using
.
Juntos, esses recursos permitem que os desenvolvedores simplifiquem e expandam os cenários onde using
podem ser aplicados.
Projeto de Execução
Usando a declaração
A linguagem permitirá que using
seja adicionado a uma declaração de variável local. Tal declaração terá o mesmo efeito que declarar a variável em uma declaração using
no mesmo local.
if (...)
{
using FileStream f = new FileStream(@"C:\source\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\source\using.md"))
{
// statements
}
}
O tempo de vida de um using
local estender-se-á até ao final do âmbito em que é declarado. Os elementos using
serão então descartados na ordem inversa em que são declarados.
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("...");
using var f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
Não há restrições em torno goto
, ou qualquer outra construção de fluxo de controle em face de uma declaração using
. Em vez disso, o código age exatamente como faria para a instrução 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;
}
}
Um local declarado em uma declaração local using
será implicitamente somente leitura. Isto corresponde ao comportamento das variáveis locais declaradas numa declaração using
.
A gramática do idioma para declarações using
será a seguinte:
local-using-declaration:
'using' type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
Restrições em torno da using
declaração.
- Pode não aparecer diretamente dentro de um rótulo
case
, mas deve estar dentro de um bloco dentro do rótulocase
. - Pode não aparecer como parte de uma declaração de variável
out
. - Deve ter um inicializador para cada declarador.
- O tipo local deve ser implicitamente conversível para
IDisposable
ou cumprir o padrãousing
.
com base em padrões usando
A linguagem adicionará a noção de um padrão descartável para os tipos ref struct
: ou seja, um ref struct
que tem um método de instância Dispose
acessível. Os tipos que se encaixam no padrão descartável podem participar de uma declaração using
sem serem obrigados a implementar IDisposable
.
ref struct Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
Isso permitirá que os desenvolvedores aproveitem using
para tipos ref struct
. Esses tipos não podem implementar interfaces em C# 8 e, portanto, não podem participar em declarações using
.
As mesmas restrições de uma instrução using
tradicional também se aplicam aqui: variáveis locais declaradas no using
são somente leitura, um valor null
não fará com que uma exceção seja lançada, etc. A geração de código será diferente apenas porque não haverá uma conversão para IDisposable
antes de chamar Dispose.
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
Para se ajustar ao padrão descartável, o método Dispose
deve ser um membro de instância acessível, sem parâmetros e ter um tipo de retorno void
. Não pode ser um método de extensão.
Considerações
Nenhuma dessas considerações foi implementada no C# 8
etiquetas de caixa sem blocos
Um using declaration
é ilegal diretamente dentro de um rótulo case
devido a complicações em torno de sua vida útil. Uma solução potencial é simplesmente dar-lhe a mesma vida útil que um out var
no mesmo local. Foi considerada a complexidade extra para a implementação do recurso e a facilidade do trabalho (basta adicionar um bloco ao rótulo case
) não justificava seguir esse caminho.
Expansões Futuras
Locais fixos
Uma declaração fixed
tem todas as propriedades das declarações using
que motivaram a capacidade de ter locais using
. Deve-se considerar a possibilidade de estender esta funcionalidade aos locais fixed
também. Aqui, as regras de validade e de ordenação devem aplicar-se igualmente bem para using
e fixed
.
C# feature specifications