CA2000: Descarte objetos antes de perder o escopo

Property valor
ID da regra CA2000
Título Descarte objetos antes de perder o escopo
Categoria Fiabilidade
A correção está quebrando ou não quebrando Sem quebra
Habilitado por padrão no .NET 8 Não

Motivo

Um objeto local de um IDisposable tipo é criado, mas o objeto não é descartado antes que todas as referências ao objeto estejam fora do escopo.

Por padrão, essa regra analisa toda a base de código, mas isso é configurável.

Descrição da regra

Se um objeto descartável não for explicitamente descartado antes que todas as referências a ele estejam fora do escopo, o objeto será descartado em algum momento indeterminado quando o coletor de lixo executar o finalizador do objeto. Como pode ocorrer um evento excecional que impedirá a execução do finalizador do objeto, o objeto deve ser explicitamente descartado.

Casos especiais

A regra CA2000 não é acionada para objetos locais dos seguintes tipos, mesmo que o objeto não seja descartado:

Passar um objeto de um desses tipos para um construtor e, em seguida, atribuí-lo a um campo indica uma transferência de propriedade de descarte para o tipo recém-construído. Ou seja, o tipo recém-construído passa a ser responsável pelo descarte do objeto. Se o código passar um objeto de um desses tipos para um construtor, nenhuma violação da regra CA2000 ocorrerá mesmo se o objeto não for descartado antes que todas as referências a ele estejam fora do escopo.

Como corrigir violações

Para corrigir uma violação dessa regra, chame Dispose o objeto antes que todas as referências a ele estejam fora do escopo.

Você pode usar a using instrução (Using no Visual Basic) para encapsular objetos que implementam IDisposable. Os objetos que são encapsulados dessa maneira são automaticamente descartados no final do using bloco. No entanto, as seguintes situações não devem ou não podem ser tratadas com uma using declaração:

  • Para retornar um objeto descartável, o objeto deve ser construído em um bloco fora de um try/finallyusing bloco.

  • Não inicialize membros de um objeto descartável no construtor de uma using instrução.

  • Quando os construtores que são protegidos por apenas um manipulador de exceção são aninhados na parte de aquisição de uma instrução, uma using falha no construtor externo pode resultar no objeto criado pelo construtor aninhado nunca sendo fechado. No exemplo a seguir, uma falha no construtor pode resultar no StreamReaderFileStream objeto nunca ser fechado. CA2000 sinaliza uma violação da regra neste caso.

    using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create)))
    { ... }
    
  • Os objetos dinâmicos devem usar um objeto de sombra para implementar o padrão de descarte de IDisposable objetos.

Quando suprimir avisos

Não suprima um aviso desta regra, a menos que:

  • Você chamou um método em seu objeto que chama Dispose, como Close.
  • O método que gerou o aviso retorna um IDisposable objeto que encapsula seu objeto.
  • O método de atribuição não tem a propriedade de eliminação; ou seja, a responsabilidade de descartar o objeto é transferida para outro objeto ou wrapper que é criado no método e retornado ao chamador.

Suprimir um aviso

Se você quiser apenas suprimir uma única violação, adicione diretivas de pré-processador ao seu arquivo de origem para desativar e, em seguida, reativar a regra.

#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000

Para desabilitar a regra de um arquivo, pasta ou projeto, defina sua gravidade como none no arquivo de configuração.

[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none

Para obter mais informações, consulte Como suprimir avisos de análise de código.

Configurar código para análise

Use as opções a seguir para configurar em quais partes da base de código executar essa regra.

Você pode configurar essas opções apenas para esta regra, para todas as regras às quais ela se aplica ou para todas as regras nesta categoria (Confiabilidade) às quais ela se aplica. Para obter mais informações, consulte Opções de configuração da regra de qualidade de código.

Excluir símbolos específicos

Você pode excluir símbolos específicos, como tipos e métodos, da análise. Por exemplo, para especificar que a regra não deve ser executada em nenhum código dentro de tipos nomeados MyType, adicione o seguinte par chave-valor a um arquivo .editorconfig em seu projeto:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

Formatos de nome de símbolo permitidos no valor da opção (separados por |):

  • Somente nome do símbolo (inclui todos os símbolos com o nome, independentemente do tipo ou namespace que o contém).
  • Nomes totalmente qualificados no formato de ID de documentação do símbolo. Cada nome de símbolo requer um prefixo de tipo de símbolo, como M: para métodos, T: para tipos e N: para namespaces.
  • .ctor para construtores e .cctor para construtores estáticos.

Exemplos:

Valor da opção Resumo
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType Corresponde a todos os símbolos denominados MyType.
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 Corresponde a todos os símbolos denominados ou MyType1MyType2.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) Corresponde ao método MyMethod específico com a assinatura totalmente qualificada especificada.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) Corresponde a métodos MyMethod1 específicos e MyMethod2 com as respetivas assinaturas totalmente qualificadas.

Excluir tipos específicos e seus tipos derivados

Você pode excluir tipos específicos e seus tipos derivados da análise. Por exemplo, para especificar que a regra não deve ser executada em nenhum método dentro de tipos nomeados MyType e seus tipos derivados, adicione o seguinte par chave-valor a um arquivo .editorconfig em seu projeto:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

Formatos de nome de símbolo permitidos no valor da opção (separados por |):

  • Somente nome do tipo (inclui todos os tipos com o nome, independentemente do tipo ou namespace que o contém).
  • Nomes totalmente qualificados no formato de ID de documentação do símbolo, com um prefixo opcionalT:.

Exemplos:

Valor da opção Resumo
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType Corresponde a todos os tipos nomeados MyType e todos os seus tipos derivados.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 Corresponde a todos os tipos nomeados ou MyType1 e MyType2 todos os seus tipos derivados.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType Corresponde a um tipo específico com um MyType determinado nome totalmente qualificado e todos os seus tipos derivados.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 Corresponde a tipos específicos e com os respetivos nomes totalmente qualificados, e MyType2 todos os seus tipos MyType1 derivados.

Exemplo 1

Se você estiver implementando um método que retorna um objeto descartável, use um try/finally block sem um catch block para garantir que o objeto esteja descartado. Usando um bloco try/finally você permite que exceções sejam geradas no ponto de falha e certifique-se de que o objeto seja descartado.

No método OpenPort1, a chamada para abrir o objeto ISerializable SerialPort ou a chamada para SomeMethod pode falhar. Um aviso CA2000 é levantado sobre esta implementação.

No método OpenPort2, dois objetos SerialPort são declarados e definidos como null:

  • tempPort, que é usado para testar se as operações do método são bem-sucedidas.

  • port, que é usado para o valor de retorno do método.

O tempPort é construído e aberto em um try bloco, e qualquer outro trabalho necessário é realizado no mesmo try bloco. No final do bloco, a try porta aberta é atribuída ao port objeto que será retornado e o tempPort objeto é definido como null.

O finally bloco verifica o valor de tempPort. Se não for null, uma operação no método falhou e tempPort é fechada para garantir que todos os recursos sejam liberados. O objeto de porta retornado conterá o objeto SerialPort aberto se as operações do método forem bem-sucedidas, ou será nulo se uma operação falhar.

public SerialPort OpenPort1(string portName)
{
   SerialPort port = new SerialPort(portName);
   port.Open();  //CA2000 fires because this might throw
   SomeMethod(); //Other method operations can fail
   return port;
}

public SerialPort OpenPort2(string portName)
{
   SerialPort tempPort = null;
   SerialPort port = null;
   try
   {
      tempPort = new SerialPort(portName);
      tempPort.Open();
      SomeMethod();
      //Add any other methods above this line
      port = tempPort;
      tempPort = null;

   }
   finally
   {
      if (tempPort != null)
      {
         tempPort.Close();
      }
   }
   return port;
}
Public Function OpenPort1(ByVal PortName As String) As SerialPort

   Dim port As New SerialPort(PortName)
   port.Open()    'CA2000 fires because this might throw
   SomeMethod()   'Other method operations can fail
   Return port

End Function

Public Function OpenPort2(ByVal PortName As String) As SerialPort

   Dim tempPort As SerialPort = Nothing
   Dim port As SerialPort = Nothing

   Try
      tempPort = New SerialPort(PortName)
      tempPort.Open()
      SomeMethod()
      'Add any other methods above this line
      port = tempPort
      tempPort = Nothing

   Finally
      If Not tempPort Is Nothing Then
         tempPort.Close()
      End If

   End Try

   Return port

End Function

Exemplo 2

Por padrão, o compilador do Visual Basic tem todos os operadores aritméticos verificar se há estouro. Portanto, qualquer operação aritmética do Visual Basic pode lançar um OverflowExceptionarquivo . Isso pode levar a violações inesperadas em regras como a CA2000. Por exemplo, a seguinte função CreateReader1 produzirá uma violação CA2000 porque o compilador do Visual Basic está emitindo uma instrução de verificação de estouro para a adição que poderia lançar uma exceção que faria com que o StreamReader não fosse descartado.

Para corrigir isso, você pode desabilitar a emissão de verificações de estouro pelo compilador do Visual Basic em seu projeto ou você pode modificar seu código como na seguinte função CreateReader2.

Para desativar a emissão de verificações de estouro, clique com o botão direito do mouse no nome do projeto no Gerenciador de Soluções e selecione Propriedades. Selecione Compilar>Opções Avançadas de Compilação e marque Remover verificações de estouro de inteiro.

Imports System.IO

Class CA2000
    Public Function CreateReader1(ByVal x As Integer) As StreamReader
        Dim local As New StreamReader("C:\Temp.txt")
        x += 1
        Return local
    End Function


    Public Function CreateReader2(ByVal x As Integer) As StreamReader
        Dim local As StreamReader = Nothing
        Dim localTemp As StreamReader = Nothing
        Try
            localTemp = New StreamReader("C:\Temp.txt")
            x += 1
            local = localTemp
            localTemp = Nothing
        Finally
            If (Not (localTemp Is Nothing)) Then
                localTemp.Dispose()
            End If
        End Try
        Return local
    End Function
End Class

Consulte também