CA2000: Descartar objetos antes de perder o escopo
Property | Valor |
---|---|
ID da regra | CA2000 |
Título | Descartar objetos antes de perder o escopo |
Categoria | Confiabilidade |
Correção interruptiva ou sem interrupção | Sem interrupção |
Habilitado por padrão no .NET 9 | Não |
Causa
Um objeto local de um tipo IDisposable é 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 descartado explicitamente 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 excepcional que impedirá a execução do finalizador do objeto, o objeto deve ser explicitamente descartado em vez disso.
Casos especiais
A regra CA2000 não é disparada para objetos locais dos seguintes tipos, mesmo que o objeto não seja descartado:
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
Passar um objeto de um desses tipos para um construtor e depois 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 agora será o responsável por descartar o objeto. Se o código passar um objeto de um desses tipos para um construtor, nenhuma violação da regra CA2000 ocorrerá mesmo que o objeto não seja 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 no 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 descartados automaticamente no final do bloco using
. No entanto, as seguintes situações não devem ou não podem ser tratadas com uma instrução using
:
Para retornar um objeto descartável, o objeto deve ser construído em um bloco
try/finally
fora de um blocousing
.Não inicialize membros de um objeto descartável no construtor de uma instrução
using
.Quando construtores protegidos por apenas um manipulador de exceção são aninhados na parte de aquisição de uma instrução
using
, uma falha no construtor externo pode fazer com que o objeto criado pelo construtor aninhado nunca seja fechado. No exemplo a seguir, uma falha no construtor StreamReader pode fazer com que o objeto FileStream nunca seja fechado. CA2000 sinaliza uma violação da regra neste caso.using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create))) { ... }
Objetos dinâmicos devem usar um objeto de sombra para implementar o padrão de descarte de objetos IDisposable.
Quando suprimir avisos
Não suprima um aviso dessa regra, a não ser que:
- Você tenha chamado um método em seu objeto que chama
Dispose
, como Close. - O método que levantou o aviso retorna um objeto IDisposable que encapsula seu objeto.
- O método de alocação não tem propriedade de descarte, ou seja, a responsabilidade de descartar o objeto é transferida para outro objeto ou wrapper criado no método e retornado ao chamador.
Suprimir um aviso
Para suprimir apenas uma violação, adicione diretivas de pré-processador ao arquivo de origem a fim de desabilitar e, em seguida, reabilitar 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 em um arquivo, uma pasta ou um projeto, defina a severidade como none
no arquivo de configuração.
[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none
Para obter mais informações, confira Como suprimir avisos de análise de código.
Configurar código para analisar
Use as opções a seguir para configurar em quais partes da base de código essa regra deve ser executada.
Você pode configurar essas opções apenas para essa regra, para todas as regras às quais ela se aplica ou para todas as regras nessa categoria (Confiabilidade) às quais ela se aplica. Para saber mais, confira Opções de configuração de regra de qualidade de código.
Excluir símbolos específicos
Você pode excluir da análise símbolos específicos, como tipos e métodos. 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 no 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 contém).
- Nomes totalmente qualificados no formato de ID de documentação do símbolo. Cada nome de símbolo requer um prefixo do tipo símbolo, como
M:
para métodos,T:
para tipos eN:
para namespaces. .ctor
para construtores e.cctor
para construtores estáticos.
Exemplos:
Valor de Opção | Resumo |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Corresponde a todos os símbolos nomeados MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Corresponde a todos os símbolos nomeados MyType1 ou MyType2 . |
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 aos métodos MyMethod1 e MyMethod2 específico com as assinaturas respectivas 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 no 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 contém).
- Nomes totalmente qualificados no formato de ID de documentação do símbolo, com um prefixo opcional
T:
.
Exemplos:
Valor de 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 MyType1 ou MyType2 e todos os seus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Corresponde a um tipo MyType específico com 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 MyType1 e MyType2 específicos com os respectivos nomes totalmente qualificados e todos os seus tipos derivados. |
Regras relacionadas
Exemplo 1
Se você estiver implementando um método que retorna um objeto descartável, use um bloco try/finally sem um bloco catch para garantir que o objeto seja descartado. Usando um bloco try/finally, você permite que exceções sejam geradas no ponto de falha e se certifica de que o objeto seja descartado.
No método OpenPort1, a chamada para abrir o SerialPort do objeto ISerializable ou a chamada para SomeMethod pode falhar. Um aviso CA2000 é gerado sobre essa implementação.
No método OpenPort2, dois objetos SerialPort são declarados e definidos como nulos:
tempPort
, que é usado para testar se as operações de método foram bem-sucedidas.port
, que é usado para o valor retornado do método.
O tempPort
é construído e aberto em um bloco try
e qualquer outro trabalho necessário é executado no mesmo bloco try
. No final do bloco try
, a porta aberta é atribuída ao objeto port
que será retornado e o objeto tempPort
é definido como null
.
O bloco finally
verifica o valor de tempPort
. Se não for nulo, uma operação no método falhará e tempPort
será fechado 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 tiverem sido 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 verificando se há estouro. Portanto, qualquer operação aritmética do Visual Basic pode gerar um OverflowException. Isso pode levar a violações inesperadas em regras como 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 gerar 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 modificar seu código como na seguinte função CreateReader2.
Para desabilitar a emissão de verificações de estouro, clique com o botão direito do mouse no nome do projeto em Gerenciador de Soluções e selecione Propriedades. Selecione Compilar>Opções avançadas de compilação e, em seguida, 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