Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Сборщик мусора среды общего языка выполнения (GC) освобождает память, используемую управляемыми объектами. Как правило, типы, использующие неуправляемые ресурсы, реализуют IDisposable или IAsyncDisposable интерфейс, чтобы разрешить восстановление неуправляемых ресурсов. После использования объекта, реализующего IDisposable, вызовите его Dispose или DisposeAsync, чтобы явно выполнить очистку. Это можно сделать одним из двух способов:
- С помощью инструкции или объявления C#
using
(Using
в Visual Basic). - Путем реализации блока
try/finally
и вызова метода Dispose или DisposeAsync вfinally
.
Это важно
Сборщик мусора не удаляет ваши объекты, поскольку он не имеет информации о IDisposable.Dispose() или IAsyncDisposable.DisposeAsync(). GC знает только, является ли объект завершенным (т. е. определяет Object.Finalize() метод), и когда необходимо вызвать метод завершения объекта. Дополнительные сведения см. в разделе Как работает функция завершения. Дополнительные сведения о реализации Dispose
и DisposeAsync
, см. в статье:
Объекты, реализующие System.IDisposable или System.IAsyncDisposable всегда должны быть должным образом удалены независимо от области переменных, если иное не указано явным образом. Типы, определяющие финализатор для освобождения неуправляемых ресурсов, обычно вызывают GC.SuppressFinalize либо из своей реализации Dispose
, либо DisposeAsync
. Вызов SuppressFinalize указывает в GC, что финализатор уже был выполнен и объект не должен предлагаться для финализации.
Инструкция using
Инструкцияusing
в C# и Using
инструкция в Visual Basic упрощают код, который необходимо записать для очистки объекта. Инструкция using
получает один или несколько ресурсов, выполняет указанные инструкции и автоматически удаляет объект. Однако инструкция using
полезна только для объектов, которые используются в области метода, в котором они созданы.
В следующем примере using
используется для создания и освобождения объекта System.IO.StreamReader.
using System.IO;
class UsingStatement
{
static void Main()
{
var buffer = new char[50];
using (StreamReader streamReader = new("file1.txt"))
{
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
}
}
Imports System.IO
Module UsingStatement
Public Sub Main()
Dim buffer(49) As Char
Using streamReader As New StreamReader("File1.txt")
Dim charsRead As Integer
Do While streamReader.Peek() <> -1
charsRead = streamReader.Read(buffer, 0, buffer.Length)
'
' Process characters read.
'
Loop
End Using
End Sub
End Module
using
Объявление — это альтернативный синтаксис объявления, доступный при удалении фигурных скобок, где область видимости является неявной.
using System.IO;
class UsingDeclaration
{
static void Main()
{
var buffer = new char[50];
using StreamReader streamReader = new("file1.txt");
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
}
StreamReader Хотя класс, реализующий IDisposable интерфейс, указывает, что он использует неуправляемый ресурс, пример явно не вызывает StreamReader.Dispose метод. Когда компилятор C# или Visual Basic встречает using
инструкцию, он выдает промежуточный язык (IL), эквивалентный следующему коду, который явно содержит try/finally
блок.
using System.IO;
class TryFinallyGenerated
{
static void Main()
{
var buffer = new char[50];
StreamReader? streamReader = null;
try
{
streamReader = new StreamReader("file1.txt");
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
finally
{
// If non-null, call the object's Dispose method.
streamReader?.Dispose();
}
}
}
Imports System.IO
Module TryFinallyGenerated
Public Sub Main()
Dim buffer(49) As Char
Dim streamReader As New StreamReader("File1.txt")
Try
Dim charsRead As Integer
Do While streamReader.Peek() <> -1
charsRead = streamReader.Read(buffer, 0, buffer.Length)
'
' Process characters read.
'
Loop
Finally
If streamReader IsNot Nothing Then DirectCast(streamReader, IDisposable).Dispose()
End Try
End Sub
End Module
Оператор C# using
также позволяет получить несколько ресурсов в одном операторе, который внутренне эквивалентен вложенным операторам using
. В следующем примере создается экземпляр двух объектов для чтения содержимого двух StreamReader разных файлов.
using System.IO;
class SingleStatementMultiple
{
static void Main()
{
var buffer1 = new char[50];
var buffer2 = new char[50];
using StreamReader version1 = new("file1.txt"),
version2 = new("file2.txt");
int charsRead1, charsRead2 = 0;
while (version1.Peek() != -1 && version2.Peek() != -1)
{
charsRead1 = version1.Read(buffer1, 0, buffer1.Length);
charsRead2 = version2.Read(buffer2, 0, buffer2.Length);
//
// Process characters read.
//
}
}
}
Блок try/finally
Вместо обёртывания блока try/finally
в инструкцию using
можно выбрать реализацию блока try/finally
напрямую. Это может быть ваш личный стиль программирования, или вы можете сделать это по одной из следующих причин:
- Включить блок
catch
для обработки исключений, выброшенных в блокеtry
. В противном случае любые исключения, вызываемые в инструкцииusing
, останутся необработанными. - Чтобы создать экземпляр объекта, реализующего IDisposable, область видимости которого не является локальной для блока, в котором он объявлен.
Следующий пример аналогичен предыдущему примеру, за исключением того, что он использует try/catch/finally
блок для создания экземпляра, использования и удаления StreamReader объекта, а также для обработки исключений, создаваемых StreamReader конструктором и его ReadToEnd методом. Код в блоке finally
проверяет, что объект, реализующий IDisposable, не является null
, перед вызовом метода Dispose. Невыполнение этого может привести к исключению во время выполнения программы.
using System;
using System.Globalization;
using System.IO;
class TryExplicitCatchFinally
{
static void Main()
{
StreamReader? streamReader = null;
try
{
streamReader = new StreamReader("file1.txt");
string contents = streamReader.ReadToEnd();
var info = new StringInfo(contents);
Console.WriteLine($"The file has {info.LengthInTextElements} text elements.");
}
catch (FileNotFoundException)
{
Console.WriteLine("The file cannot be found.");
}
catch (IOException)
{
Console.WriteLine("An I/O error has occurred.");
}
catch (OutOfMemoryException)
{
Console.WriteLine("There is insufficient memory to read the file.");
}
finally
{
streamReader?.Dispose();
}
}
}
Imports System.Globalization
Imports System.IO
Module TryExplicitCatchFinally
Sub Main()
Dim streamReader As StreamReader = Nothing
Try
streamReader = New StreamReader("file1.txt")
Dim contents As String = streamReader.ReadToEnd()
Dim info As StringInfo = New StringInfo(contents)
Console.WriteLine($"The file has {info.LengthInTextElements} text elements.")
Catch e As FileNotFoundException
Console.WriteLine("The file cannot be found.")
Catch e As IOException
Console.WriteLine("An I/O error has occurred.")
Catch e As OutOfMemoryException
Console.WriteLine("There is insufficient memory to read the file.")
Finally
If streamReader IsNot Nothing Then streamReader.Dispose()
End Try
End Sub
End Module
Вы можете следовать этому базовому шаблону, если вы решили реализовать или должны реализовать try/finally
блок, так как ваш язык программирования не поддерживает using
оператор, но разрешает прямые вызовы метода Dispose.
Элементы экземпляра IDisposable
Если класс владеет полем экземпляра или свойством, и его тип реализует IDisposable, то класс также должен реализовать IDisposable. Дополнительные сведения см. в разделе "Реализация каскадного удаления".