Как я могу узнать, когда мои типы `IDisposable` не были явно удалены - PullRequest
4 голосов
/ 23 июня 2010

Это трудно найти в типах времени разработки / компиляции, которые можно идентифицировать, но которые расположены неправильно Какие методы существуют во время выполнения, чтобы найти их?

Ответы [ 2 ]

7 голосов
/ 23 июня 2010

Хорошей практикой является реализация 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()
1 голос
/ 23 июня 2010

Инструменты анализа кода, такие как FxCop (входит в состав Team Editions Visual Studio или в виде бесплатной загрузки), могут обнаружить это.

Хотя иногда могут быть ложные негативы / позитивы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...