Использование вложенных IDisposable объектов
Я бы хотел рассказать о моем маленьком эксперименте с использованием вложенных (паттерн Decorator) System.IDisposable объектов на примере с System.Xml.XmlReader и System.IO.FileStream. О том, как грамотно, на мой взгляд, использовать их изложено под катом.
Поставим банальную задачу: создать метод порождающий объект класса System.Xml.XmlDocument с данными, загруженными из файла «test.xml» (Опустим содержимое файла и структуру Xml). Данную задачу можно сделать очень просто, используя метод Load(string filename) класса XmlDocument, но у нас тема про использование вложенных IDisposable объектов, поэтому сделаем это с помощью того же метода, но принимающего в качестве параметра объект класса System.Xml.XmlReader.
Для этого нам нужно создать объект класса FileStream. Затем создать объект класса XmlReader и вызвать метод Load, передав в него созданный объект. И вернуть созданный XmlDocument. Создать XmlReader можно двумя подходами: статический метод Create или создание реализации Syste.Xml.XmlTextReader. Кусочек кода:
XmlDocument GetXmlDocument() { using (XmlReader xmlReader = XmlReader.Create(new FileStream("test.xml"))) { var xmlDocument = new XmlDocument(); xmlDocument.Load(xmlReader); return xmlDocument; } }
В принципе, код без ошибок?
А вот и нет. После наблюдений в режиме отладчика, оказалось, что у объекта класса FileStream метод Dispose не вызывается после выхода из блока с using. Кстати, созданный объект методом Create — не объект класса XmlTextReader.
Тогда я решил воспользоваться созданием экземпляра XmlTextReader.
Кусочек кода
XmlReader.Create(new FileStream("test.xml"))
меняем на
new XmlTextReader(new FileStream("test.xml"))
Теперь все работает (оба объекта освобождают ресурсы после выхода из блока using). Проверял на .NET 4.0.
О чем пост? О том, что нужно аккуратно использовать такие конструкции.
Использование декорированных конструкций было результатом изучения Java с ее системой ввода-вывода, где много построено на паттерне Decorator, а также попытка ухода от спагетти-кода с использованием множества вложенных using и try/catch.
Про интерфейс IDisposable изложено много, но на всякий случай: System.IDisposable в MSDN.