Подтвердить что ты не робот

С# как реализовать метод Dispose

Мне нужен совет по реализации метода Dispose.

В нашем приложении пользователь разрабатывает собственный пользовательский интерфейс. У меня есть окно предварительного просмотра, которое показывает, как будет выглядеть пользовательский интерфейс. Весь объект, нарисованный в этом пользовательском интерфейсе, в конечном итоге вытекает из общего базового класса ScreenObject. Мой менеджер предварительного просмотра содержит ссылку на один объект для ScreenGrid, который является объектом сетки для всей области предварительного просмотра.

Вопрос № 1

Некоторые из моих производных классов экрана занимают неуправляемые ресурсы, такие как соединение с базой данных, растровое изображение и элемент управления WebBrowser. Эти классы должны распоряжаться этими объектами. Я создал виртуальный метод Dispose в базовом классе базового ScreenObject, а затем реализовал переопределяющий метод Dispose в каждом из производных классов, которые удерживаются на неуправляемых ресурсах. Однако прямо сейчас я создал метод Dispose, я не реализую IDisposable. Должен ли я реализовать IDisposable? Если да, то как его реализовать?

  • Только на производных классах, у которых есть неуправляемые ресурсы
  • Базовый класс и производные классы, у которых есть неуправляемые ресурсы OR
  • Базовый класс и все производные классы, включая те, у которых нет неуправляемых ресурсов

Неправильно ли использовать виртуальный метод Dispose в базовом классе, который не имеет неуправляемых ресурсов, чтобы вы могли воспользоваться полиморфизмом?

Вопрос № 2

При чтении об методе Dispose и интерфейсе IDispoable Microsoft заявляет, что объект-утилита должен вызывать метод Dispose для своего родителя. Родитель вызовет его для своего родителя и так далее. Для меня это кажется обратным. Я могу захотеть избавиться от ребенка, но сохранил его родителя.

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

Я здесь не так, или я чего-то не хватает?

4b9b3361

Ответ 1

Вопрос 1: Внедрите IDisposable, используя следующий шаблон:

public class MyClass : IDisposable
{
    bool disposed;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
        }
        //dispose unmanaged resources
        disposed = true;
    }

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

Вопрос 2: Microsoft означает, что вызовы производного класса выставляют на нем родительский класс. Владелец экземпляра только вызывает Dispose для самого производного типа.

Пример (сокращенный):

class Parent : IDisposable 
{
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
        }
        //dispose unmanaged resources
        disposed = true;
    }

}
class Child : Parent, IDisposable 
{ 
    protected override void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
            base.Dispose(disposing);
        }
        //dispose unmanaged resources
        disposed = true;
    }

}
class Owner:IDisposable
{
    Child child = new Child();
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                if(child!=null)
                {
                    child.Dispose();
                }
            }
        }
        //dispose unmanaged ressources
        disposed = true;
    }
}

Владелец вызывает Dispose только для ребенка, но не для родителя. Ребенок отвечает за вызов Dispose на родителя.

Ответ 2

для вопроса 1:
На основе типов объектов, которые вы перечисляете (т.е. Базы данных, веб-браузера, растрового изображения и т.д.), Это только управляемые ресурсы, что касается .NET. Таким образом, вы должны реализовать IDisposable в любом классе, который имеет одноразовые типы в качестве членов. Если они являются локально объявленными экземплярами, вы просто вызываете "using()" на них. Хотя эти экземпляры, которые вы упомянули, имеют неуправляемые ресурсы под ними, это абстрагируется от вас .NET через используемые вами типы. Поскольку вы используете только управляемые типы, вы должны реализовать IDisposable , но без финализатора. Вам нужно всего лишь реализовать финализатор, если у вас действительно есть неуправляемые ресурсы в качестве членов класса.

для вопроса 2:
Кажется, что вы вводите в заблуждение наследование (а) с агрегированием/сдерживанием (имеет а). Например, если "Контейнер" содержит одноразовый ресурс в качестве члена класса, он называется агрегированием/сдерживанием. Таким образом, вызов "base.Dispose()" в реализации IDisposable Container не имеет ничего общего с удалением одноразового ресурса внутри контейнера. Вы должны помнить, что если класс происходит из Контейнера, скажите "DerivedContainer", что это экземпляр контейнера, хотя и с дополнительными членами и/или функциональностью. Таким образом, любой экземпляр "DerivedContainer" имеет все члены, которые делает его базовый класс "Контейнер". Если вы никогда не вызывали base.Dispose(), одноразовый ресурс в "Контейнере" не был бы выпущен должным образом (это было бы фактически GC, но по многим причинам это плохой способ просто "позволить .NET позаботиться об этом" ) пожалуйста, обратитесь к моему опубликованному ответу Неправильная ли практика зависит от автоматического сборщика мусора .NET?.

Если вы не вызвали базовый класс Dispose(), у вас получится частично удаленный объект (расположенный в производном классе, но не в базовом классе) - очень плохой сценарий. Поэтому очень важно вызвать базовый класс Dispose().

У меня есть образец лучших практик, который я разработал (с большим опытом и отладки памяти), написанными на моем блоге в качестве примера. В нем показано, как реализовать IDisposable в базовом классе, а также в производном классе:

http://dave-black.blogspot.com/2011/03/how-do-you-properly-implement.html

Если это сообщение полезно, отметьте его как таковое. НТН