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

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

2 голосов
/ 09 июня 2009

У меня проблемы с шаблоном C # '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). В C ++, где аргументы могут иметь значения по умолчанию, я вижу это, но в C # я потерян. Я думаю, что мой отладчик не показывает мне, что на самом деле происходит.

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

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

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

Ответы [ 4 ]

4 голосов
/ 10 июня 2009

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

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

Прочитайте это для некоторого фона: 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;
}
2 голосов
/ 09 июня 2009

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

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

1 голос
/ 09 июня 2009

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

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

0 голосов
/ 10 июня 2009

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

* 1003 Е.Г. *

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

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