CA2000: 범위를 벗어나기 전에 개체를 삭제하십시오.
속성 | 값 |
---|---|
규칙 ID | CA2000 |
제목 | 범위를 벗어나기 전에 개체를 삭제하세요. |
범주 | 신뢰성 |
수정 사항이 주요 변경인지 여부 | 주요 변경 아님 |
.NET 9에서 기본적으로 사용 | 아니요 |
원인
IDisposable 형식의 로컬 개체를 만들지만 개체에 대한 모든 참조가 범위를 벗어나기 전에 개체가 삭제되지 않습니다.
기본적으로 이 규칙은 전체 코드베이스를 분석하지만 이는 구성 가능합니다.
규칙 설명
삭제 가능한 개체에 대한 모든 참조가 범위를 벗어나기 전에 해당 개체가 명시적으로 삭제되지 않으면 가비지 수집기가 개체의 종료자를 실행할 때 확정되지 않은 시점에 개체가 삭제됩니다. 개체의 종료자가 실행될 수 없도록 하는 예외적인 이벤트가 발생할 수 있으므로 대신 개체를 명시적으로 삭제해야 합니다.
특별 케이스
규칙 CA2000은 개체가 삭제되지 않은 경우에도 다음 형식의 로컬 개체에 대해 발생하지 않습니다.
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
이러한 형식 중 하나인 개체를 생성자에 전달한 후 필드에 할당하면 새로 생성된 형식으로 ‘삭제 소유권이 전송’됨을 나타냅니다. 즉, 새로 생성된 형식이 이제 개체의 삭제를 담당합니다. 코드가 이러한 형식 중 하나인 개체를 생성자에 전달하는 경우에는 개체에 대한 모든 참조가 범위를 벗어나기 전에 개체가 삭제되지 않아도 규칙 CA2000의 위반이 발생하지 않습니다.
위반 문제를 해결하는 방법
이 규칙의 위반 문제를 해결하려면 개체에 대한 모든 참조가 범위를 벗어나기 전에 개체에서 Dispose를 호출합니다.
using
문(Using
Visual Basic의 경우 )을 사용하여 IDisposable을 구현하는 개체를 래핑할 수 있습니다. 이런 방식으로 래핑되는 개체는 using
블록의 끝부분에서 자동으로 삭제됩니다. 그러나 다음과 같은 경우는 using
문을 사용하여 처리할 수 없거나 처리해서는 안 됩니다.
삭제 가능한 개체를 반환하려면 블록 외부 블록에서 개체를
try/finally
using
생성해야 합니다.using
문의 생성자에서 삭제 가능한 개체의 멤버를 초기화하지 마세요.하나의 예외 처리기에서만 보호되는 생성자가
using
문의 획득 파트에서 중첩되면 외부 생성자의 오류로 인해 중첩된 생성자에서 만들어진 개체가 닫히지 않을 수 있습니다. 다음 예제에서는 StreamReader 생성자의 오류로 인해 FileStream 개체가 닫히지 않습니다. 이 경우 CA2000은 규칙의 위반에 플래그를 지정합니다.using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create))) { ... }
동적 개체는 섀도 개체를 사용하여 IDisposable 개체의 삭제 패턴을 구현해야 합니다.
경고를 표시하지 않는 경우
다음의 경우를 제외하고는 이 규칙의 경고를 표시해야 합니다.
- 개체
Dispose
에서 호출하는 메서드(예: Close.)를 호출했습니다. - 경고를 발생시킨 메서드는 개체를 IDisposable 래핑하는 개체를 반환합니다.
- 할당 메서드에는 소유권이 삭제되지 않습니다. 즉, 개체를 삭제해야 하는 책임은 메서드에서 만들어지고 호출자에게 반환되는 다른 개체 또는 래퍼로 전송됩니다.
경고 표시 안 함
단일 위반만 표시하지 않으려면 원본 파일에 전처리기 지시문을 추가하여 규칙을 사용하지 않도록 설정한 후 다시 사용하도록 설정합니다.
#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000
파일, 폴더 또는 프로젝트에 대한 규칙을 사용하지 않도록 설정하려면 구성 파일에서 심각도를 none
으로 설정합니다.
[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none
자세한 내용은 방법: 코드 분석 경고 표시 안 함을 참조하세요.
분석할 코드 구성
다음 옵션을 사용하여 이 규칙이 실행될 코드베이스 부분을 구성합니다.
이 규칙, 적용되는 모든 규칙 또는 적용되는 이 범주의 모든 규칙(안정성)에 대해 이러한 옵션을 구성할 수 있습니다. 자세한 내용은 코드 품질 규칙 구성 옵션을 참조하세요.
특정 기호 제외
분석에서 형식 및 메서드와 같은 특정 기호를 제외할 수 있습니다. 예를 들어 MyType
이라는 형식 내 코드에서 규칙을 실행하지 않도록 지정하려면 프로젝트의 .editorconfig 파일에 다음 키-값 쌍을 추가합니다.
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
옵션 값의 허용되는 기호 이름 형식(|
로 구분):
- 기호 이름만(포함하는 형식 또는 네임스페이스와 관계없이 해당 이름의 모든 기호 포함).
- 기호의 설명서 ID 형식에 있는 정규화된 이름. 각 기호 이름에는 메서드의 경우
M:
, 형식의 경우T:
, 네임스페이스의 경우N:
과 같은 기호 종류 접두사가 필요합니다. - 생성자의 경우
.ctor
이고 정적 생성자의 경우.cctor
입니다.
예:
옵션 값 | 요약 |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
MyType 이라는 모든 기호와 일치합니다. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
MyType1 또는 MyType2 라는 모든 기호와 일치합니다. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
특정 메서드 MyMethod 를 지정된 정규화된 시그니처와 비교합니다. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
특정 메서드 MyMethod1 및 MyMethod2 를 개별 정규화된 시그니처와 비교합니다. |
특정 형식 및 해당 파생 형식 제외
분석에서 특정 형식과 해당 파생 형식을 제외할 수 있습니다. 예를 들어 MyType
이라는 형식 및 해당 파생 형식 내에 있는 메서드에서 규칙이 실행되지 않도록 지정하려면 프로젝트의 .editorconfig 파일에 다음 키-값 쌍을 추가합니다.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
옵션 값의 허용되는 기호 이름 형식(|
로 구분):
- 형식 이름만(포함하는 형식이나 네임스페이스와 관계없이 해당 이름의 모든 형식 포함)
- 기호의 설명서 ID 형식에 있는 정규화된 이름(선택적
T:
접두사 포함)
예:
옵션 값 | 요약 |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
MyType 이라는 모든 형식 및 모든 해당 파생 형식과 일치합니다. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
MyType1 또는 MyType2 라는 모든 형식 및 모든 해당 파생 형식과 일치합니다. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
지정된 정규화된 이름의 특정 MyType 형식 및 모든 해당 파생 형식과 일치합니다. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
개별 정규화된 이름의 특정 MyType1 , MyType2 형식 및 모든 해당 파생 형식과 일치합니다. |
관련 규칙
예 1
삭제 가능한 개체를 반환하는 메서드를 구현하는 경우 catch 블록 없이 try/finally 블록을 사용하여 개체가 삭제되었는지 확인합니다. try/finally 블록을 사용하여 오류 지점에서 예외가 발생하도록 하고 개체가 삭제되었는지 확인합니다.
OpenPort1 메서드에서 ISerializable 개체 SerialPort를 여는 호출이나 SomeMethod에 대한 호출이 실패할 수 있습니다. 이 구현에서는 CA2000 경고가 발생합니다.
OpenPort2 메서드에서는 두 개의 SerialPort 개체를 선언하고 null로 설정합니다.
tempPort
- 메서드 작업이 성공하는지 테스트하는 데 사용됩니다.port
- 메서드의 반환 값에 사용됩니다.
tempPort
는 try
블록에서 생성되고 열리며 다른 모든 필수 작업도 동일한 try
블록에서 수행됩니다. try
블록의 끝부분에서 열린 포트는 반환되는 port
개체에 할당되고 tempPort
개체는 null
로 설정됩니다.
finally
블록은 tempPort
의 값을 확인합니다. null이 아닌 경우 메서드의 작업이 실패한 것이며 리소스가 해제되도록 tempPort
가 닫힙니다. 메서드의 작업이 성공한 경우에는 반환된 포트 개체에 열린 SerialPort 개체가 포함되고 작업이 실패한 경우에는 null이 됩니다.
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
예제 2
기본적으로 Visual Basic 컴파일러의 모든 산술 연산자는 오버플로를 검사합니다. 따라서 Visual Basic 산술 연산에서 OverflowException이 throw될 수 있습니다. 이로 인해 CA2000과 같은 규칙에서 예기치 않은 위반이 발생할 수 있습니다. 예를 들어 다음 CreateReader1 함수는 CA2000 위반을 생성합니다. 이는 StreamReader가 삭제되지 않도록 하는 예외를 throw할 수 있는 더하기에 대해 Visual Basic 컴파일러에서 오버플로 검사 명령을 내보내기 때문입니다.
이 위반을 해결하려면 프로젝트에서 Visual Basic 컴파일러의 오버플로 검사 내보내기를 사용하지 않도록 설정하거나 다음 CreateReader2 함수와 같이 코드를 수정할 수 있습니다.
오버플로 검사 내보내기를 사용하지 않도록 설정하려면 솔루션 탐색기 프로젝트 이름을 마우스 오른쪽 단추로 클릭한 다음 속성을 선택합니다. 컴파일>고급 컴파일 옵션을 선택한 다음 정수 오버플로 제거 검사를 선택합니다.
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
참고 항목
.NET