Как использовать шаблон IDisposable в Windows Form

Я читал о шаблоне IDisposable в этой статье и хочу чтобы реализовать его в моем приложении Windows Form. Как мы знаем, в классе windows form .Designer.cs уже есть метод Dispose.

private System.ComponentModel.IContainer components = null;

protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        components.Dispose();
    }
    base.Dispose(disposing);
}

а в классе .cs я использую типизированный набор данных для чтения и сохранения данных.

public partial class frmCustomerList
{
    private MyTypedDataSet ds = new MyTypedDataSet();
    ...
}

Итак, как реализовать IDisposable для удаления MyTypedDataSet? Если я реализую IDisposable в frmCustomerList и реализую его интерфейс

public partial class frmCustomerList : IDisposable
{
    private MyTypedDataSet ds = new MyTypedDataSet();
    void Dispose()
    {
       ds.Dispose();
    }
}

как насчет метода Dispose(bool disposing) в .Designer.cs?


person Willy    schedule 16.05.2014    source источник
comment
Зачем нужно утилизировать MyTypedDataSet?   -  person Ben Aaronson    schedule 16.05.2014
comment
Я не думаю, что вам нужно IDisposable в форме. Если у вас нет неуправляемой памяти, избавляться от нее не нужно.   -  person Ben N    schedule 16.05.2014
comment
Почему вы хотите реализовать IDisposable в форме? Конечно, вы могли бы просто отреагировать на событие FormClosed, чтобы произвести уборку?   -  person Enigmativity    schedule 16.05.2014
comment
@BenAaronson, потому что я хочу очистить DataSet, на мой взгляд, если это не так, если я работаю со многими формами и не удаляю DataSet, это может привести к замедлению работы приложения   -  person Willy    schedule 16.05.2014
comment
@Enigmativity да, я могу очистить любые ресурсы (DataSet) в FormClosed, но я просто хочу знать, какой способ подходит?   -  person Willy    schedule 16.05.2014
comment
@Willy - FormClosed (или FormClosing) было бы подходящим способом. Я бы не рекомендовал менять код конструктора, чтобы IDisposable заработал.   -  person Enigmativity    schedule 16.05.2014
comment
@Willy Сборщик мусора сделает это за вас. Просто убедитесь, что никакие ссылки на набор данных не сохраняются после того, как вы закончите с ним.   -  person Ben Aaronson    schedule 16.05.2014


Ответы (3)


Я бы избавился от любых членов формы, используя одно из событий формы, например

http://msdn.microsoft.com/en-us/library/system.windows.forms.form.onclosed%28v=vs.110%29.aspx

e.g

protected override void OnClosed(EventArgs e)
{
    base.OnClosed(e);

    if (ds != null)
        ds.Dispose();
}
person Mick    schedule 16.05.2014
comment
Привет, @Mick, почему вы используете защищенное переопределение void OnClosed (EventArgs e), а не private void frmCustomerList_FormClosed (отправитель объекта, FormClosedEventArgs e)? Есть ли опасения? - person Willy; 21.05.2014
comment
Вы можете использовать и то, и другое. Функциональной разницы быть не должно. Подписка на закрытое событие на самом деле, вероятно, безопаснее, поскольку вы можете забыть вызвать метод базового класса, который вызовет проблемы. - person Mick; 22.05.2014
comment
Это работает, пока форма открыта. Форму можно создать (т.е. пройти через ее конструктор) без отображения. - person Guillermo Prandi; 14.08.2020

Если вы посмотрите в файл Designer.cs и ниже метод удаления, вы увидите это

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {

Только InializeComponent() предупреждается об отсутствии изменений. Вы можете вырезать (не копировать) и вставить protected override void Dispose(bool disposing) из файла дизайнера и без проблем переместить его в основной файл кода, просто не забудьте оставить часть components.Dispose(); вместе с любыми одноразовыми объектами, которые вы добавляете через дизайнер будет помещен в эту коллекцию для утилизации.

public partial class frmCustomerList
{
    private MyTypedDataSet ds = new MyTypedDataSet();

    protected override void Dispose(bool disposing)
    {
        ds.Dispose();

        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    //The rest of your frmCustomerList.cs file.
}
person Scott Chamberlain    schedule 16.05.2014
comment
Это очень плохая идея. Изменение кода, сгенерированного дизайнером, - не лучшая идея, а очень плохая. - person Mick; 16.05.2014
comment
@Mick Visual Studio предназначена для обработки этого изменения. Я бы никогда не рекомендовал менять что-либо внутри региона #region Windows Form Designer generated code, поэтому они поместили функцию Dispose() за пределы региона. - person Scott Chamberlain; 16.05.2014
comment
Я все равно не стал бы трогать Designer.cs независимо от регионов в файле, файл создается дизайнером. Изменения в файле можно легко потерять, и есть другие способы решить эту проблему, не требующие редактирования файла. - person Mick; 16.05.2014
comment
Это лучший ответ для меня, так как мне не нужно подавлять CA2213. Голосовать за. Спасибо, Скотт. - person Biscuits; 17.04.2015
comment
Это должен быть принятый ответ ... это действительно правильный метод. - person Nyerguds; 17.10.2019

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

public class ComplexResourceHolder : IDisposable
{

    private IntPtr buffer; // unmanaged memory buffer
    private SafeHandle resource; // disposable handle to a resource

    public IntPtr Buffer { get { return buffer; } set { buffer = value; } }

    public ComplexResourceHolder()
    {
        this.buffer = ... // allocates memory
        this.resource = ... // allocates the resource
    }

    protected virtual void Dispose(bool disposing)
    {
        ReleaseBuffer(buffer); // release unmanaged memory
    if (disposing)
    { 
        // release other disposable objects
        if (resource!= null)
           resource.Dispose();
    }
}

~ ComplexResourceHolder(){
    Dispose(false);
}

public void Dispose(){
    Dispose(true);
    GC.SuppressFinalize(this);
}

}

Посетите MSDN для лучшего понимания Dispose (bool) переопределение финализатора. И эта ссылка о неуправляемых ресурсах будет быть полезным, потому что это первая причина, по которой вы должны использовать IDisposable.

Вы можете задаться вопросом, использовать такие конструкции, как показано ниже, если класс наследует IDisposable:

using (ComplexResourceHolder crh = new ComplexResourceHolder())
{
    //Do something with buffer for an instance
    //crh.Buffer =
}

Метод Dispose будет вызываться автоматически после закрывающего тега '}'.

person Wallstrider    schedule 16.05.2014
comment
Это вводит в заблуждение, если член класса реализует dispose, вы должны реализовать dispose в классе, а не только тогда, когда ваш класс напрямую имеет дело с неуправляемыми ресурсами. Даже с управляемыми ресурсами классы часто реализуют утилизацию, чтобы обеспечить своевременный сбор дорогостоящих управляемых ресурсов. - person Mick; 16.05.2014
comment
Сборщик мусора сделает всю работу так быстро, как только сможет. Даже если вы вызываете GC.SuppressFinalize (this), это не означает, что GC немедленно его соберет. Он будет собираться всякий раз, когда GC считает, что может его собрать. Я протестировал изменения памяти после использования утилизации на управляемых ресурсах и без нее. Тайминги почти такие же. - person Wallstrider; 16.05.2014
comment
Большинство классов .NET не реализуют IDisposable. Почему? Потому что в этом нет необходимости. - person Wallstrider; 16.05.2014
comment
Все элементы управления из System.Windows.Forms реализуют IDisposable. Вот почему все формы содержат метод Dispose. - person Wallstrider; 16.05.2014
comment
Мы программируем в параллельных вселенных. Если я вижу, что создается экземпляр объекта, который реализует IDispose, а объект-владелец никогда не вызывает Dispose для этого объекта или не заключен в оператор using, это ошибка в моих книгах. Я пойду еще дальше и упомяну, что сборщику мусора требуется помощь для сбора мусора, особенно на таких платформах, как Windows Phone и Windows CE. Реализация Dispose и разъединение объектов (установка переменных в null) действительно имеет значение. Циклические зависимости могут создавать блоки классов, которые никогда не собираются. - person Mick; 19.05.2014
comment
Я не думаю, что вы думаете, что это что-то необычное. Я видел большие утечки памяти во многих .NET-приложениях, написанных людьми, которые, вероятно, с вами согласились бы. Хорошим примером является сама Visual Studio, она написана на .NET, на моей машине открывается, потребляя 100 КБ, с ней работаешь день, даже после закрытия каждого файла это может занять 2 гига. Я бы не стал нанимать разработчика .NET, который не верит, что в приложениях .NET возможна утечка управляемой памяти. - person Mick; 19.05.2014
comment
Я согласен с вашими 2 постами выше. Но я попытался ответить конкретно на эту тему. @Willy не упомянул, какой класс он хочет удалить, на какой платформе он работает и т. Д. Поэтому я счел ненужным реализовывать IDisposable. Я хочу сказать, что вы должны использовать Dispose, когда у вас действительно есть утечки памяти и т. Д., Но это не означает, что вам нужно реализовать IDisposable для каждого имеющегося у вас класса. : D - person Wallstrider; 19.05.2014