CA2000: Usuwanie obiektów przed utratą zakresu
Właściwości | Wartość |
---|---|
Identyfikator reguły | CA2000 |
Tytuł | Likwiduj obiekty przed utratą zakresu |
Kategoria | Niezawodność |
Poprawka powodująca niezgodność lub niezgodność | Niezgodność |
Domyślnie włączone na platformie .NET 9 | Nie. |
Przyczyna
Tworzony jest obiekt IDisposable lokalny typu, ale obiekt nie jest usuwany, zanim wszystkie odwołania do obiektu są poza zakresem.
Domyślnie ta reguła analizuje całą bazę kodu, ale można to skonfigurować.
Opis reguły
Jeśli obiekt jednorazowy nie jest jawnie usuwany, zanim wszystkie odwołania do niego są poza zakresem, obiekt zostanie usunięty w określonym czasie, gdy moduł odśmiecanie pamięci uruchamia finalizator obiektu. Ponieważ może wystąpić wyjątkowe zdarzenie, które uniemożliwi uruchomienie finalizatora obiektu, obiekt powinien zostać jawnie usunięty.
Przypadki szczególne
Reguła CA2000 nie jest uruchamiana dla obiektów lokalnych następujących typów, nawet jeśli obiekt nie jest usuwany:
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
Przekazanie obiektu jednego z tych typów do konstruktora, a następnie przypisanie go do pola wskazuje przeniesienie własności usuwania do nowo skonstruowanego typu. Oznacza to, że nowo skonstruowany typ jest teraz odpowiedzialny za usuwanie obiektu. Jeśli kod przekazuje obiekt jednego z tych typów do konstruktora, żadne naruszenie reguły CA2000 nie występuje, nawet jeśli obiekt nie jest usuwany przed wszystkimi odwołaniami do niego są poza zakresem.
Jak naprawić naruszenia
Aby naprawić naruszenie tej reguły, wywołaj Dispose obiekt przed wszystkimi odwołaniami do niego są poza zakresem.
Możesz użyć instrukcji using
(Using
w Visual Basic), aby opakowować obiekty implementujące IDisposable. Obiekty, które są opakowane w ten sposób, są automatycznie usuwane na końcu using
bloku. Jednak następujące sytuacje nie powinny być obsługiwane lub nie mogą być obsługiwane za pomocą instrukcji using
:
Aby zwrócić obiekt jednorazowy, obiekt musi być skonstruowany w
try/finally
bloku poza blokiemusing
.Nie inicjuj elementów członkowskich obiektu jednorazowego w konstruktorze instrukcji
using
.Gdy konstruktory chronione tylko przez jedną procedurę obsługi wyjątków są zagnieżdżone w części
using
pozyskiwania instrukcji, błąd w konstruktorze zewnętrznym może spowodować, że obiekt utworzony przez zagnieżdżony konstruktor nigdy nie jest zamknięty. W poniższym przykładzie błąd konstruktora StreamReader może spowodować FileStream , że obiekt nigdy nie zostanie zamknięty. CA2000 flaguje naruszenie reguły w tym przypadku.using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create))) { ... }
Obiekty dynamiczne powinny używać obiektu w tle do implementowania wzorca IDisposable usuwania obiektów.
Kiedy pomijać ostrzeżenia
Nie pomijaj ostrzeżenia z tej reguły, chyba że:
- Wywołaliśmy metodę w obiekcie, która wywołuje
Dispose
metodę , taką jak Close. - Metoda, która zgłosiła ostrzeżenie, zwraca IDisposable obiekt, który opakowuje obiekt.
- Metoda przydzielania nie ma własności usuwania; oznacza to, że odpowiedzialność za usuwanie obiektu jest przenoszona do innego obiektu lub otoki utworzonej w metodzie i zwracana do obiektu wywołującego.
Pomijanie ostrzeżenia
Jeśli chcesz po prostu pominąć pojedyncze naruszenie, dodaj dyrektywy preprocesora do pliku źródłowego, aby wyłączyć, a następnie ponownie włączyć regułę.
#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000
Aby wyłączyć regułę dla pliku, folderu lub projektu, ustaw jego ważność na none
w pliku konfiguracji.
[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none
Aby uzyskać więcej informacji, zobacz Jak pominąć ostrzeżenia dotyczące analizy kodu.
Konfigurowanie kodu do analizowania
Użyj poniższych opcji, aby skonfigurować, które części bazy kodu mają być uruchamiane w tej regule.
Można skonfigurować te opcje tylko dla tej reguły, dla wszystkich reguł, których dotyczy, lub dla wszystkich reguł w tej kategorii (niezawodność), których dotyczy. Aby uzyskać więcej informacji, zobacz Opcje konfiguracji reguły jakości kodu.
Wykluczanie określonych symboli
Z analizy można wykluczyć określone symbole, takie jak typy i metody. Aby na przykład określić, że reguła nie powinna być uruchamiana w żadnym kodzie w typach o nazwie MyType
, dodaj następującą parę klucz-wartość do pliku editorconfig w projekcie:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Dozwolone formaty nazw symboli w wartości opcji (oddzielone przez |
):
- Tylko nazwa symbolu (zawiera wszystkie symbole o nazwie, niezależnie od typu zawierającego lub przestrzeni nazw).
- W pełni kwalifikowane nazwy w formacie identyfikatora dokumentacji symbolu. Każda nazwa symboli wymaga prefiksu typu symboli, takiego jak
M:
metody,T:
dla typów iN:
przestrzeni nazw. .ctor
dla konstruktorów i.cctor
konstruktorów statycznych.
Przykłady:
Wartość opcji | Podsumowanie |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Pasuje do wszystkich symboli o nazwie MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Pasuje do wszystkich symboli o nazwie MyType1 lub MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Pasuje do określonej metody MyMethod z określonym w pełni kwalifikowanym podpisem. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Pasuje do określonych metod MyMethod1 i MyMethod2 z odpowiednimi w pełni kwalifikowanymi podpisami. |
Wykluczanie określonych typów i ich typów pochodnych
Z analizy można wykluczyć określone typy i ich typy pochodne. Aby na przykład określić, że reguła nie powinna być uruchamiana na żadnych metodach w typach nazwanych MyType
i ich typach pochodnych, dodaj następującą parę klucz-wartość do pliku .editorconfig w projekcie:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Dozwolone formaty nazw symboli w wartości opcji (oddzielone przez |
):
- Nazwa typu (zawiera tylko wszystkie typy o nazwie, niezależnie od typu zawierającego lub przestrzeni nazw).
- W pełni kwalifikowane nazwy w formacie identyfikatora dokumentacji symbolu z opcjonalnym
T:
prefiksem.
Przykłady:
Wartość opcji | Podsumowanie |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Pasuje do wszystkich typów nazwanych MyType i wszystkich ich typów pochodnych. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Dopasuje wszystkie typy o nazwie MyType1 lub MyType2 i wszystkie ich typy pochodne. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Pasuje do określonego typu MyType z daną w pełni kwalifikowaną nazwą i wszystkimi jego typami pochodnymi. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Pasuje do określonych typów MyType1 i MyType2 z odpowiednimi w pełni kwalifikowanymi nazwami i wszystkimi ich typami pochodnymi. |
Powiązane reguły
Przykład 1
Jeśli implementujesz metodę zwracającą jednorazowy obiekt, użyj bloku try/finally bez bloku catch, aby upewnić się, że obiekt jest usuwany. Korzystając z bloku try/finally, można zezwolić na wywoływanie wyjątków w punkcie błędu i upewnij się, że obiekt jest usuwany.
W metodzie OpenPort1 wywołanie w celu otwarcia obiektu ISerializable SerialPort lub wywołanie metody SomeMethod może zakończyć się niepowodzeniem. W tej implementacji zostanie zgłoszone ostrzeżenie CA2000.
W metodzie OpenPort2 dwa obiekty SerialPort są zadeklarowane i ustawione na wartość null:
tempPort
, który służy do testowania, czy operacje metody kończą się powodzeniem.port
, który jest używany dla wartości zwracanej metody.
Obiekt tempPort
jest skonstruowany i otwarty w try
bloku, a każda inna wymagana praca jest wykonywana w tym samym try
bloku. Na końcu try
bloku otwarty port jest przypisywany do port
obiektu, który zostanie zwrócony, a tempPort
obiekt ma wartość null
.
Blok finally
sprawdza wartość tempPort
. Jeśli nie ma wartości null, operacja w metodzie nie powiodła się i tempPort
jest zamknięta, aby upewnić się, że wszystkie zasoby zostały zwolnione. Zwrócony obiekt portu będzie zawierać otwarty obiekt SerialPort, jeśli operacje metody zakończyły się pomyślnie lub będzie mieć wartość null, jeśli operacja nie powiodła się.
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
Przykład 2
Domyślnie kompilator języka Visual Basic ma wszystkie operatory arytmetyczne sprawdzające przepełnienie. W związku z tym każda operacja arytmetyczna języka Visual Basic może zgłosić OverflowExceptionbłąd . Może to prowadzić do nieoczekiwanych naruszeń reguł, takich jak CA2000. Na przykład następująca funkcja CreateReader1 spowoduje naruszenie CA2000, ponieważ kompilator języka Visual Basic emituje instrukcję sprawdzania przepełnienia dla dodania, która może zgłosić wyjątek, który może spowodować, że element StreamReader nie zostanie usunięty.
Aby rozwiązać ten problem, można wyłączyć emitowanie kontroli przepełnienia przez kompilator języka Visual Basic w projekcie lub zmodyfikować kod, tak jak w poniższej funkcji CreateReader2.
Aby wyłączyć emitowanie kontroli przepełnienia, kliknij prawym przyciskiem myszy nazwę projektu w Eksplorator rozwiązań, a następnie wybierz polecenie Właściwości. Wybierz pozycję Kompiluj zaawansowane opcje kompilowania>, a następnie zaznacz pole Wyboru Usuń przepełnienie liczb całkowitych.
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