Compartilhar via


"uso baseado em padrões" e "declarações de uso"

Observação

Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ela inclui alterações de especificação propostas, juntamente com as informações necessárias durante o design e o desenvolvimento do recurso. Esses artigos são publicados até que as alterações de especificação propostas sejam finalizadas e incorporadas na especificação ECMA atual.

Pode haver algumas divergências entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da reunião de design de idioma (LDM).

Você pode saber mais sobre o processo de adoção de speclets de recursos no padrão de linguagem C# no artigo sobre as especificações de .

Problema do especialista: https://github.com/dotnet/csharplang/issues/114

Resumo

A linguagem adicionará dois novos recursos ao redor 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 instrução using à linguagem.

Motivação

A instrução using é uma ferramenta eficaz para o gerenciamento de recursos hoje, mas requer uma quantidade considerável de formalidade. Métodos que têm vários recursos para gerenciar podem ficar sobrecarregados sintaticamente com uma série de instruções using. Essa carga de sintaxe é suficiente para que a maioria das diretrizes de estilo de codificação tenha explicitamente uma exceção entre colchetes para esse 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, o using baseado em padrão permite que os desenvolvedores expandam o conjunto de tipos que podem participar aqui. Em muitos casos, eliminando a necessidade de criar tipos encapsuladores que existem apenas para possibilitar o uso de valores em uma instrução using.

Juntos, esses recursos permitem que os desenvolvedores simplifiquem e expandam os cenários em que using podem ser aplicados.

Projeto detalhado

usando declaração

A linguagem permitirá que using seja adicionado a uma declaração de variável local. Essa declaração terá o mesmo efeito que declarar a variável em uma instruçã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 se estenderá até o final do escopo no qual ele é declarado. Os using locais serão descartados na ordem inversa em que foram 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 relacionadas ao goto ou a qualquer outra construção de fluxo de controle em relação a uma declaração de using. Em vez disso, o código age exatamente como faria para a declaraçã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 de leitura. Isso corresponde ao comportamento das variáveis locais declaradas em uma instrução using.

A gramática da linguagem para declarações de 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 declaração de using:

  • Não pode 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 atender ao padrão using.

uso baseado em padrões

A linguagem adicionará a noção de um padrão descartável para tipos de ref struct: esse é um ref struct que tem um método de instância de Dispose acessível. Os tipos que se ajustam ao padrão descartável podem participar de uma instrução ou declaração using sem a necessidade de implementar IDisposable.

ref struct Resource
{ 
    public void Dispose() { ... }
}

using (var r = new Resource())
{
    // statements
}

Isso permitirá que os desenvolvedores utilizem using para tipos ref struct. Esses tipos não podem implementar interfaces no C# 8 e, portanto, não podem participar nas instruções using.

As mesmas restrições de uma declaração using tradicional se aplicam aqui também: variáveis ​​locais declaradas em using são somente leitura, um valor null não causará uma exceção 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 adequar 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 em C# 8

rótulos de casos sem blocos

Um using declaration é ilegal diretamente dentro de um rótulo de case devido a complicações em torno de seu tempo de vida real. Uma possível solução é simplesmente oferecer a ele o mesmo tempo de vida de um out var no mesmo local. Foi considerado que a complexidade adicional para a implementação do recurso e a facilidade da solução alternativa (basta adicionar um bloco ao rótulo case) não justificam seguir por esse caminho.

Expansões futuras

locais fixos

Uma instrução fixed possui todas as propriedades das instruções using que motivaram a possibilidade de ter using locais. Deve-se considerar a extensão desse recurso também para locais fixed. As regras de tempo de vida e ordenação devem se aplicar igualmente para using e fixed aqui.