CA2000: Usuwanie obiektów przed utratą zakresu
TypeName |
DisposeObjectsBeforeLosingScope |
CheckId |
CA2000 |
Kategoria |
Microsoft.Reliability |
Zmiana kluczowa |
Niekluczowa |
Przyczyna
Lokalny obiekt typu IDisposable został utworzony, ale obiekt nie jest usuwany, aż wszystkie odwołania do obiektu będą poza zakresem.
Opis reguły
Jeśli obiekt usuwalny nie jest jawnie usuwany zanim wszystkie odwołania do niego są poza zakresem, obiekt zostanie usunięty w nieokreślonym czasie, gdy moduł usuwający elementy bezużyteczne pamięci uruchomi finalizator obiektu.Ponieważ może wystąpić nieoczekiwane zdarzenie, które uniemożliwi uruchomienie finalizatora, obiekt należy jawnie usunąć.
Jak naprawić naruszenia
Aby naprawić naruszenie tej zasady, należy wywołać dla obiektu Dispose zanim wszystkie odwołania do tego obiektu znajdą się poza zakresem.
Należy zauważyć, że można użyć instrukcji using (Using w Visual Basic) aby otoczyć obiekty implementujące IDisposable.Obiekty, które są pakowane w ten sposób automatycznie zostaną usunięte po zamknięciu bloku using.
Poniżej opisano sytuacje, w których instrukcja using nie wystarcza do ochrony obiektów IDisposable i może spowodować wystąpienie CA2000.
Zwracanie obiektu usuwalnego wymaga, aby obiekt został skonstruowany w bloku try/finally poza blokiem using.
Inicjowanie elementów członkowskich usuwalnego obiektu nie powinno być dokonywane w konstruktorze przy użyciu instrukcji using.
Zagnieżdżone konstruktory, które są chronione tylko przez jeden blok obsługi wyjątków.Na przykład:
using (StreamReader sr = new StreamReader(new FileStream("C:\myfile.txt", FileMode.Create))) { ... }
powoduje CA2000, ponieważ błąd podczas tworzenia obiektu StreamReader może spowodować, że obiekt FileStream nigdy nie zostanie zamknięty.
Obiekty dynamiczne powinny używać obiektu cienia do zaimplementowania wzorca usuwanie obiektów IDisposable.
Kiedy pominąć ostrzeżenia
Nie należy pomijać ostrzeżenia tej reguły, chyba że wywołano metodę na obiekcie, która wywołuje Dispose, jak na przykład Close, bądź jeśli metoda, która wywołała ostrzeżenie zwróci obiekt IDisposable otaczający Twój obiekt.
Powiązane reguły
CA2213: Pola usuwalne powinny zostać usunięte
CA2202: Nie należy usuwać obiektów wiele razy
Przykład
Jeśli implementujesz metodę, która zwraca obiekt usuwalny, użyj bloku try/finally bez bloku catch aby upewnić się, że obiekt jest usuwany.Poprzez użycie bloku try/finally, zezwala się na zgłaszanie wyjątków w punkcie usterki i zapewnia się, że obiekt jest usuwany.
W metodzie OpenPort1 wywołanie otwarcia obiektu ISerializable portu SerialPort lub wywołanie SomeMethod może się nie powieść.Ostrzeżenie CA2000 jest wywoływane dla tej implementacji.
W metodzie OpenPort2 dwa obiekty portu SerialPort są deklarowane i ustawiane na wartość null:
tempPort, służący do sprawdzenia, że operacje metody powiodły się.
port, który jest używany dla wartości zwracanej metody.
tempPort jest tworzony i otwierany w bloku try oraz wszelka inna wymagana praca jest wykonywana w tym samym bloku try.Na koniec bloku try otwarty port jest przypisywany do obiektu port, który zostanie zwrócony i obiekt tempPort jest ustawiany na wartość null.
Blok finally sprawdza wartość tempPort.Jeśli nie jest równa null, operacja w metodzie nie powidła się i tempPort zostaje zamknięty, aby upewnić się, że wszystkie zasoby zostaną zwolnione.Obiekt zwrócony portu będzie zawierać otwarty obiekt portu SerialPort jeśli operacje metody powiodą się lub przyjmie wartość null, jeśli operacja nie powiedzie się.
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
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
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;
}
Domyślnie kompilator Visual Basic sprawdza przepełnienie dla wszystkich operatorów arytmetycznych.Dlatego każda operacja arytmetyczna Visual Basic może zgłosić OverflowException.Mogłoby to doprowadzić do nieoczekiwanego naruszenia zasad, takich jak CA2000.Na przykład poniższa funkcja CreateReader1 spowoduje naruszenie CA2000 ponieważ kompilator języka Visual Basic emituje instrukcję sprawdzania przepełnienia dla dodawania, która może zgłosić wyjątek, który może spowodować, że obiekt StreamReader nie zostanie usunięty.
Aby rozwiązać ten problem, można wyłączyć emisję kontroli przepełnienia przez kompilator Visual Basic w projekcie lub można zmodyfikować kod tak jak w funkcji CreateReader2.
Aby wyłączyć emisję sprawdzania przepełnienia, kliknij prawym przyciskiem myszy nazwę projektu w oknie Eksploratora rozwiązania, a następnie kliknij przycisk Właściwości.Kliknij Skompiluj, kliknij Zaawansowane opcje kompilacji, a następnie sprawdź Usuń sprawdzenia przepełnienia liczb całkowitych.