C # метод утилизации

2

У меня возникают трудности с шаблоном С# Dispose. У меня здесь 3 класса: класс управления, форма и класс хранения данных.

Класс управления может (если необходимо) использовать форму для запроса пользователя для ввода. Форма загружает данные из файла, которые пользователь может затем изменить. Когда он закрыт, форма должна сохранить эти данные. Класс хранения данных реализует .Dispose(), который делает именно это - записывает изменения на диск.

Поскольку этот класс хранения данных (StoredInfo) является членом формы (MyForm), MyForm также должен реализовать .Dispose(), чтобы вызвать StoredInfo.Dispose. Это то, что дает мне проблемы. Мой класс управления, в нем код:

Form.Dispose();
Form = null;

И моя форма:

// As written by MSVS. The exception is OK - I just want this to get called.
#region IDisposable Members

public void IDisposable.Dispose()
{
    throw new NotImplementedException();
}

#endregion

... но метод Form.Dispose() никогда не вызывается. Выйдя с отладчиком, выполнение выполняется:

Connector.Dispose() // The management class
    Form.Dispose()
Form.Dispose(bool disposing) // (1) Some method designer wrote?
    if (disposing && (components != null))
    {
        components.Dispose();
    }
    base.Dispose(disposing);
Connector.Dispose() // Back to the management class!
    Form = null;

Мы почему-то никогда не вызывали .Dispose, но вместо этого вызываем .Dispose(bool). В С++, где аргументы могут иметь значения по умолчанию, я могу это увидеть, но в С# я потерян. Мое лучшее предположение заключается в том, что мой отладчик не показывает мне, что на самом деле происходит.

Теперь, глядя на иерархию классов, я вижу другие классы, которые реализуют IDisposable, поэтому должен быть другой объект Dispose(). Это не виртуально, поэтому я не уверен, почему я не получаю ошибки компилятора. Я попытался переопределить метод .Dispose(bool), так как он получает вызов и является виртуальным, но с этим:

protected override void Dispose(bool disposing)
{
    StoredHosts.Dispose();
}

Я получаю "Тип ConnectorForm" уже определяет член, называемый "Dispose" с теми же типами параметров ", который, да, я предполагаю, что он... в коде конструктора. Так что не вариант. Поэтому вернемся к вызову Dispose(). Но как? Мне не хватает простой простоты и мощности и детерминизма деструкторов С++ на данный момент.

  • 1
    Почему бы вам не сбросить данные о закрытом событии?
  • 0
    @unknown: Вы действительно должны опубликовать это как ответ - я обдумываю это. Я подвергаю сомнению законность выполнения дискового ввода-вывода в .Dispose () (поскольку Dispose является своего рода деструктором, вы не должны вызывать исключения в деструкторе, и я делаю то, что очень хорошо может вызвать исключения. Я должен спросить себя: если форма заканчивается насильственно (то есть, по исключению) - я хочу сохранить данные?
Теги:
dispose

4 ответа

4

Мастер Windows Form ставит специальные "региональные директивы" вокруг кода, который вы не должны изменять, поэтому вы можете изменять материал Dispose столько, сколько хотите, до тех пор, пока вы остаетесь внутри шаблона.

Подумайте о IDisposable как способе создания деструкторов .NET. Пока все разработчики правильно это понимают, результат может быть эквивалентен деструкторам С++ (на самом деле С++/CLI генерирует метод Dispose из объявлений деструктора, и я очень скучаю по этой функции на С#).

Прочитайте это для некоторого фона: http://msdn.microsoft.com/en-us/magazine/cc163392.aspx

Есть несколько вещей, о которых нужно знать. Во-первых, параметр disposing указывает на то, что в кат-контексте вызывается виртуальный метод Dispose(bool). Если это false, то DO NOT DO ANYTHING! Это означает, что вы вызываетесь из потока финализатора. Это почти никогда не бывает полезным, и это исторический недостаток в дизайне этого шаблона, потому что у него есть что-то 99,99% полезное (логика детерминированного уничтожения), смешанное с чем-то полезным только на 0,01% (обычная бесплатная потоковая обработка собственных ресурсов), как если бы они были лучшими друзьями.

Итак, разместите свой собственный код очистки внутри ветки if (disposing).

Во-вторых, обратите внимание на то, как код, созданный мастером, проверяет, не является ли ссылка объекта не нулевой, прежде чем называть Dispose. Согласно определению IDisposable, вы должны ожидать, что Dispose будет вызван несколько раз без причины в одном экземпляре.

Итак, вы хотите сделать это:

if (Form != null)
{
    Form.Dispose();
    Form = null;
}
  • 0
    Большой! Я использовал именно это, чтобы избавиться от созданных не дизайнером объектов. Однако я переместил метод из файла .Designer.cs, чтобы лучше реализовать его на случай, если дизайнер ошибется.
2

Класс Form (или, если быть точнее, класс Component) определяет свой собственный метод Dispose, который вызывает виртуальный метод Dispose(bool disposing)

Вам нужно переместить созданный конструктором метод Dispose (который переопределяет виртуальный метод и вызывается Component.Dispose) из файла Designer, а затем помещает StoredHosts.Dispose(); внутри него.

1

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

Дизайнер не волшебный. Он просто пишет нормальный С#.

  • 0
    Помимо «не изменяйте содержимое этого метода с помощью редактора кода», но это другой метод. Будет ли дизайнер сдувать мой метод, когда я буду редактировать его?
  • 1
    Однако я считаю, что вы должны быть осторожны, так как дизайнер может решить перезаписать ваши изменения. Если я в конечном итоге что-то изменю в файле .designer, я переместлю его в файл .cs, поэтому, когда Designer вносит больше изменений, он оставляет то, что я изменил.
Показать ещё 3 комментария
0

написав void IDisposable.Dispose(), вы фактически сообщаете runtime вызывать эту конкретную версию метода Dispose тогда и только тогда, когда переменная имеет тип IDisposable.

например.

Form f1 = new YourForm();
IDispoable f2 = new YourForm();

f1.Dispose(); //call to public void Dispose()
f2.Dispose(); //call to void IDisposable.Dispose()

Ещё вопросы

Сообщество Overcoder
Наверх
Меню