Расположите, когда это назовут?

Рассмотрите следующий код:

namespace DisposeTest
{
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Calling Test");

            Test();

            Console.WriteLine("Call to Test done");
        }

        static void Test()
        {
            DisposeImplementation di = new DisposeImplementation();
        }
    }

    internal class DisposeImplementation : IDisposable
    {
        ~DisposeImplementation()
        {
            Console.WriteLine("~ in DisposeImplementation instance called");
        }
        public void Dispose()
        {
            Console.WriteLine("Dispose in DisposeImplementation instance called");
        }
    }
}

Расположение просто никогда не добирается, звонил, даже если я поместил цикл ожидания после Test(); вызов. Так, чтобы вполне высосал. Я хочу записать класс, который прост и очень прост в использовании, чтобы удостовериться, что каждый возможный ресурс очищен. Я не хочу помещать ту ответственность перед пользователем моего класса.

Возможное решение: использовать using, или вызов Располагает меня (basicly то же). Я могу вынудить пользователя использовать использование? Или я могу вынудить расположение быть названным?

Вызов GC.Collect(); после Test(); не работает также.

Помещение di кому: null не вызывает Dispose также. Deconstructor ДЕЙСТВИТЕЛЬНО работает, таким образом, объект добирается, вскрыл противоречия, когда он выходит Test()

Хорошо парни, это ясно теперь!

Спасибо всем за Ваши ответы! Я добавлю предупреждение в комментарии!

29
задан Venkat 7 June 2019 в 12:41
поделиться

6 ответов

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

Вы не можете этого сделать. Управление памятью просто не предназначено для размещения ресурсов, которые не являются конкретно памятью.

Шаблон IDisposable предназначен для разработчиков как способ сообщить объекту, когда они закончили с ним, вместо того, чтобы управление памятью пыталось выяснить это, используя такие вещи, как подсчет ссылок.

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

21
ответ дан 28 November 2019 в 00:46
поделиться

Вам придется вызвать Dispose явно или обернув объект в using оператор. Пример:

using (var di = new DisposeImplementation())
{
}

Возможное решение: использовать using, или вызвать Dispose самостоятельно (в основном то же самое).

Использование using - это то же самое, что вызов Dispose внутри блока finally.

2
ответ дан 28 November 2019 в 00:46
поделиться

Все ответы (более или менее) верны, вот пример:

static void Test()
{
    using (DisposeImplementation di = new DisposeImplementation())
    {
        // Do stuff with di
    }
}

Ручной вызов Dispose также будет работать, но преимущество оператора using состоит в том, что объект также будет удален, когда вы покинете блок управления, потому что возникнет исключение.

Вы можете добавить финализатор, который обрабатывает удаление ресурсов в случае, если кто-то «забывает» использовать интерфейс IDisposable:

public class DisposeImplementation : IDisposable
{    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    }

    ~DisposeImplementation()
    {
        Dispose(false);
    }
}

См. этот вопрос для получения дополнительной информации. Однако это просто компенсация для людей, которые неправильно используют ваш класс :) Я предлагаю вам добавить большой жирный вызов Debug.Fail () в Finalizer, чтобы предупредить разработчика об их ошибке.

Если вы решите реализовать шаблон, вы увидите, что GC.Collect () запустит удаление.

13
ответ дан 28 November 2019 в 00:46
поделиться

Вы должны избавиться от него самостоятельно, либо вызвав метод Dispose , либо используя , используя . Помните, это не деконструктор!

Если вы не можете доверять пользователям вашего класса в правильном распределении ресурсов, они, вероятно, все равно испортят что-то еще.

1
ответ дан 28 November 2019 в 00:46
поделиться

Dispose не вызывается автоматически. Вам нужно использовать предложение using , чтобы обернуть использование или вызвать его вручную.

См. http://msdn.microsoft.com/en-us/library/aa664736%28VS.71%29.aspx

И просто чтобы упредить другую идею, которая может у вас возникнуть: вы не можете позвонить по dispose из деструктора ... Я пробовал это некоторое время назад в проекте.

1
ответ дан 28 November 2019 в 00:46
поделиться

Используйте это как образец / шаблон для ваших классов

public class MyClass : IDisposable
{
    private bool disposed = false;

    // Implement IDisposable.
    // Do not make this method virtual.
    // A derived class should not be able to override this method.
    public void Dispose()
    {
        Dispose(true);
        // This object will be cleaned up by the Dispose method.
        // Therefore, you should call GC.SupressFinalize to
        // take this object off the finalization queue
        // and prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    // Dispose(bool disposing) executes in two distinct scenarios.
    // If disposing equals true, the method has been called directly
    // or indirectly by a user's code. Managed and unmanaged resources
    // can be disposed.
    // If disposing equals false, the method has been called by the
    // runtime from inside the finalizer and you should not reference
    // other objects. Only unmanaged resources can be disposed.
    private void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called.
        if (!this.disposed)
        {
            // If disposing equals true, dispose all managed
            // and unmanaged resources.
            if (disposing)
            {
                // Dispose managed resources.                
                ......
            }

            // Call the appropriate methods to clean up
            // unmanaged resources here.
            // If disposing is false,
            // only the following code is executed.
            ...........................

            // Note disposing has been done.
            disposed = true;
        }
    }

    // Use C# destructor syntax for finalization code.
    // This destructor will run only if the Dispose method
    // does not get called.
    // It gives your base class the opportunity to finalize.
    // Do not provide destructors in types derived from this class.
    ~MyClass()
    {
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(false) is optimal in terms of
        // readability and maintainability.
        Dispose(false);
    }
}

И, конечно же, как упоминалось другими, не забывайте о с использованием блока (...) {} .

7
ответ дан 28 November 2019 в 00:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: