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:
- 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, 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/finally
using
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 eN:
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 MyType1 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 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 opcional
T:
.
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. |
Regras conexas
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