Partilhar via


"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ótulo case.
  • 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ão using.

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.