Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
| Propriedade | valor |
|---|---|
| ID da regra | CA2000 |
| Título | Descarte objetos antes de perder o alcance |
| Categoria | Fiabilidade |
| A correção causa interrupção ou não | Ininterrupto |
| Habilitado por padrão no .NET 10 | Não |
| Línguas aplicáveis | C# e Visual Basic |
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 responsabilidade 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 no objeto antes de todas as referências a ele saírem 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
try/finallybloco fora de umusingbloco.Não inicialize componentes de um objeto descartável no construtor de uma
usingdeclaraçã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
usinginstrução, uma falha no construtor externo pode resultar no objeto criado pelo construtor aninhado nunca sendo fechado. Neste exemplo, uma falha no StreamReader construtor pode resultar no FileStream objeto nunca ser encerrado. 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
Utilize as opções abaixo para configurar em quais partes da base de código esta regra deve ser executada e quando a posse do recurso deve ser transferida.
- Excluir símbolos específicos
- Excluir tipos específicos e seus tipos derivados
- Configurar transferência de propriedade com disposição
Além disso, as seguintes outras opções relacionadas à análise de fluxo de dados se aplicam a essa regra:
- dispose_analysis_kind
- interprocedural_analysis_kind
- max_interprocedural_lambda_or_local_function_call_chain
- max_interprocedural_method_call_chain
- points_to_analysis_kind
- copy_analysis
- contagem_de_iterações_suficiente_para_algoritmo_KDF_fraco
Você pode configurar essas opções apenas para esta regra, para todas as regras às quais elas se aplicam ou para todas as regras nesta categoria (Confiabilidade) às quais elas se aplicam. 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 definindo a opção excluded_symbol_names. 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
Observação
Substitua a parte XXXX do CAXXXX pelo ID da regra aplicável.
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. -
.ctorpara construtores e.cctorpara 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 MyType1 ou MyType2. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Combina o 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) |
Correlaciona métodos MyMethod1 e MyMethod2 específicos 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 definindo a opção excluded_type_names_with_derived_types. 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
Observação
Substitua a parte XXXX do CAXXXX pelo ID da regra aplicável.
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 como 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 um 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 |
Correlaciona tipos MyType1 e MyType2 específicos com os respetivos nomes totalmente qualificados e todos os seus tipos derivados. |
Configurar a transferência de propriedade de descarte
As opções dispose_ownership_transfer_at_constructor e dispose_ownership_transfer_at_method_call configuram a transferência de propriedade de descarte.
Por exemplo, para especificar que a regra transfere a propriedade de argumentos passados aos construtores, adicione o seguinte par chave-valor a um arquivo de .editorconfig em seu projeto:
dotnet_code_quality.CAXXXX.dispose_ownership_transfer_at_constructor = true
Observação
Substitua a parte XXXX do CAXXXX pelo ID da regra aplicável.
descartar_transferência_de_propriedade_no_construtor
Considere o exemplo de código a seguir.
class A : IDisposable
{
public void Dispose() { }
}
class Test
{
DisposableOwnerType M1()
{
return new DisposableOwnerType(new A());
}
}
- Se
dotnet_code_quality.dispose_ownership_transfer_at_constructorestiver definido comotrue, a propriedade da alocaçãonew A()será transferida para a instânciaDisposableOwnerTyperetornada. - Se
dotnet_code_quality.dispose_ownership_transfer_at_constructorestiver definido parafalse,Test.M1()tem a propriedade de descarte paranew A()e resulta numa violação doCA2000por uma fuga de descarte.
descartar_transferência_de_propriedade_na_chamada_de_método
Considere o exemplo de código a seguir.
class Test
{
void M1()
{
TransferDisposeOwnership(new A());
}
}
- Se
dotnet_code_quality.dispose_ownership_transfer_at_method_callestiver definido comotrue, a propriedade da alocaçãonew A()será transferida para o métodoTransferDisposeOwnership. - Se
dotnet_code_quality.dispose_ownership_transfer_at_method_callestiver definido comofalse,Test.M1()tem a propriedade de descarte paranew A()e resulta numa violação deCA2000devido a um vazamento de descarte.
Regras conexas
Exemplo 1
Se estiver a implementar 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 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 porta aberta é atribuída ao objeto port que será retornado, e o objeto tempPort é 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 faz com que todos os operadores aritméticos verifiquem se há overflow. Portanto, qualquer operação aritmética do Visual Basic pode lançar uma exceção OverflowException. 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 pode lançar uma exceção e impedir que o StreamReader seja descartado.
Para corrigir isso, pode-se desabilitar a realização das verificações de estouro pelo compilador do Visual Basic no seu projeto ou modificar o seu código como na função CreateReader2 seguinte.
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