Хорошей практикой является реализация IDisposable
, если ваш тип требует ресурсов, , но , это просто хорошая практика , и не может быть принудительно применен компилятором .
Одна вещь, которую вы можете сделать, чтобы сделать злоупотребления IDisposable
s более заметными, это сделать их throw
или assert
в finalizer
(помните, что если ваш тип расположен правильно, финализатор выиграл не вызывается , потому что вы вызвали GC.SuppressFinalize
в вашем методе утилизации). Следующая программа показывает ошибку в окне вывода отладчика, когда приложение завершает работу, потому что Hog
расположен неправильно.
class Program
{
static void Main(string[] args)
{
new Hog( ) ;
}
}
class Hog : IDisposable
{
public void Dispose( )
{
Dispose( true ) ;
GC.SuppressFinalize( this ) ;
}
protected virtual void Dispose( bool disposing )
{
GC.SuppressFinalize( this );
}
~Hog( )
{
Debug.Fail( @"You didn't dispose me!" ) ;
Dispose( false ) ;
}
}
В отладчике вы увидите следующую ошибку:
---- DEBUG ASSERTION FAILED ----
---- Assert Short Message ----
You didn't dispose me!
---- Assert Long Message ----
at Hog.Finalize()
, но , если вы правильно использовали одноразовый предмет, например:
static void Main(string[] args)
{
using (new Hog())
;
}
... ты ничего не увидишь.
Чтобы сделать вещи еще более полезными, вы можете записать текущую трассировку стека в конструкторе и вывести ее в деструктор. Так что новый, более полезный Hog
будет выглядеть так:
class Hog : IDisposable
{
readonly StackTrace _stackTrace ;
public Hog( )
{
#if DEBUG
_stackTrace = new StackTrace();
#endif
}
public void Dispose( )
{
Dispose( true ) ;
GC.SuppressFinalize( this ) ;
}
protected virtual void Dispose( bool disposing )
{
GC.SuppressFinalize( this );
}
~Hog( )
{
#if DEBUG
Debug.WriteLine("FinalizableObject was not disposed" + _stackTrace.ToString());
#endif
Dispose( false ) ;
}
}
и его использование (без утилизации) даст вам это в окне вывода отладчика:
FinalizableObject was not disposed at ConsoleApplication1.Hog..ctor()
at ConsoleApplication1.Program.Main(String[] args)
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()