C# Language
Интерфейс IDisposable
Поиск…
замечания
Клиенты класса, реализующие
IDisposable
могут быть уверены, что они вызовут методDispose
когда они будут завершены с использованием объекта. В CLR ничего не найдено, что непосредственно ищет объекты для методаDispose
для вызова.Нет необходимости реализовывать финализатор, если ваш объект содержит только управляемые ресурсы. Обязательно вызывайте
Dispose
во всех объектах, которые использует ваш класс, когда вы реализуете свой собственный методDispose
.Рекомендуется сделать класс безопасным для нескольких вызовов
Dispose
, хотя в идеале его следует вызывать только один раз. Этого можно добиться, добавив в свой классprivate bool
переменнуюprivate bool
и установив значениеtrue
когда был запущен методDispose
.
В классе, который содержит только управляемые ресурсы
Управляемые ресурсы - это ресурсы, которые сообщают сборщики мусора времени выполнения и находятся под контролем. Существует много классов, доступных в BCL, например, таких как SqlConnection
который является классом-оболочкой для неуправляемого ресурса. Эти классы уже реализуют интерфейс IDisposable
- это зависит от вашего кода, чтобы очистить их, когда вы закончите.
Нет необходимости реализовывать финализатор, если ваш класс содержит только управляемые ресурсы.
public class ObjectWithManagedResourcesOnly : IDisposable
{
private SqlConnection sqlConnection = new SqlConnection();
public void Dispose()
{
sqlConnection.Dispose();
}
}
В классе с управляемыми и неуправляемыми ресурсами
Важно, чтобы финализация игнорировала управляемые ресурсы. Финализатор работает в другом потоке - возможно, что управляемые объекты больше не существуют к моменту завершения финализатора. Реализация защищенного метода Dispose(bool)
является обычной практикой для обеспечения того, что управляемые ресурсы не имеют метода Dispose
вызванного из финализатора.
public class ManagedAndUnmanagedObject : IDisposable
{
private SqlConnection sqlConnection = new SqlConnection();
private UnmanagedHandle unmanagedHandle = Win32.SomeUnmanagedResource();
private bool disposed;
public void Dispose()
{
Dispose(true); // client called dispose
GC.SuppressFinalize(this); // tell the GC to not execute the Finalizer
}
protected virtual void Dispose(bool disposeManaged)
{
if (!disposed)
{
if (disposeManaged)
{
if (sqlConnection != null)
{
sqlConnection.Dispose();
}
}
unmanagedHandle.Release();
disposed = true;
}
}
~ManagedAndUnmanagedObject()
{
Dispose(false);
}
}
IDisposable, Dispose
.NET Framework определяет интерфейс для типов, требующих метода сбрасывания:
public interface IDisposable
{
void Dispose();
}
Dispose()
в основном используется для очистки ресурсов, например, неуправляемых ссылок. Однако также может быть полезно принудительно распоряжаться другими ресурсами, даже если они управляются. Вместо того, чтобы ждать, пока GC в конечном итоге также очистит ваше соединение с базой данных, вы можете убедиться, что это сделано в вашей собственной реализации Dispose()
.
public void Dispose()
{
if (null != this.CurrentDatabaseConnection)
{
this.CurrentDatabaseConnection.Dispose();
this.CurrentDatabaseConnection = null;
}
}
Когда вам нужно напрямую обращаться к неуправляемым ресурсам, таким как неуправляемые указатели или ресурсы win32, создайте класс, наследующий от SafeHandle
и используйте соглашения / инструменты этого класса для этого.
В унаследованном классе с управляемыми ресурсами
Довольно часто можно создать класс, который реализует IDisposable
, а затем выводит классы, которые также содержат управляемые ресурсы. Рекомендуется пометить метод Dispose
ключевым словом virtual
чтобы клиенты могли очищать любые ресурсы, которыми они могут владеть.
public class Parent : IDisposable
{
private ManagedResource parentManagedResource = new ManagedResource();
public virtual void Dispose()
{
if (parentManagedResource != null)
{
parentManagedResource.Dispose();
}
}
}
public class Child : Parent
{
private ManagedResource childManagedResource = new ManagedResource();
public override void Dispose()
{
if (childManagedResource != null)
{
childManagedResource.Dispose();
}
//clean up the parent's resources
base.Dispose();
}
}
использование ключевого слова
Когда объект реализует интерфейс IDisposable
, он может быть создан в синтаксисе using
:
using (var foo = new Foo())
{
// do foo stuff
} // when it reaches here foo.Dispose() will get called
public class Foo : IDisposable
{
public void Dispose()
{
Console.WriteLine("dispose called");
}
}
using
синтаксического сахара для блока try/finally
; приведенное выше использование будет примерно переводить:
{
var foo = new Foo();
try
{
// do foo stuff
}
finally
{
if (foo != null)
((IDisposable)foo).Dispose();
}
}