использование (IDisposable obj = new ...) в C # для записи блоков кода в потоке (например, XML) - PullRequest
7 голосов
/ 01 марта 2012

Я начал использовать классы, реализующие IDisposable, для записи блоков в потоках с помощью оператора using.Это полезно, чтобы сохранить правильное вложение и избежать отсутствующих или неправильно размещенных начальных / конечных частей.

По сути, конструктор записывает начало блока (например, открывающий тег XML), Dispose () - конец (например, закрытие).Тег XML).Примером является приведенный ниже UsableXmlElement (он предназначен для больших XML, поэтому в LINQ to XML или XmlDocument в памяти нет параметров).

Однако эти IDisposable не реализуют изощренный шаблон, рекомендованный Microsoft, с разделителем-разрушителем / финализаторомУдалите (bool) метод и GC.SuppressFinalize ().Утилизация просто записывает конечный элемент, и все.

Есть ли какая-то обратная сторона этого или это хороший способ поддерживать правильное вложение элементов?

class UsableXmlElement : IDisposable
{
    private XmlWriter _xwriter;

    public UsableXmlElement(string name, XmlWriter xmlWriter)
    {
        _xwriter = xmlWriter;
        _xwriter.WriteStartElement(name);
    }

    public void WriteAttribute<T>(string name, T value)
    {
        _xwriter.WriteStartAttribute(name);
        _xwriter.WriteValue(value);
        _xwriter.WriteEndAttribute();
    }

    public void WriteValue<T>(T value)
    {
        _xwriter.WriteValue(value);
    }

    public void Dispose()
    {
        _xwriter.WriteEndElement();
    }
}

Использованиекак это:

var xWriter = new XmlWriter(...)

using(var rootElement = new UsableXmlElement("RootElement", xWriter)
{
   rootElement.WriteAttribute("DocVersion", 123)
   using(var innerElement = new UsableXmlElement("InnerElement", xwriter)
   {
       // write anything inside Inner element
   }
}

В результате:

<RootElement DocVersion="123">
    <InnerElement>
       <!-- anything -->
    </InnerElement>
</RootElement>

Ответы [ 3 ]

3 голосов
/ 01 марта 2012

Основным недостатком, который я вижу (кроме нестандартного использования оператора using, возможно, нарушающего «принцип наименьшего удивления»), является то, что он будет пытаться многократно писать все вложенные конечные теги в случае возникновения исключенияby your XmlWriter.

По крайней мере, теоретически, вы можете получить исключение при записи внутреннего конечного тега, за которым последуют успешные записи внешних конечных тегов в блоки "finally", сгенерированные операторами using.Это приведет к неверному выводу.

2 голосов
/ 01 марта 2012

Есть ли обратная сторона этого,

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

или это хороший способ поддерживать правильное вложение элементов?*

Да.Вы можете использовать System.Web.Mvc.Html.MvcForm в качестве ссылки.

эти IDisposable не реализуют сложный шаблон, рекомендованный Microsoft

Этот «полный» шаблон является правильным, но устаревшим.Он описывает только ситуацию с «голым» неуправляемым ресурсом.Официальные ссылки для работы только с управляемыми ресурсами, к сожалению, не предоставлены.

1 голос
/ 01 марта 2012

Сложный шаблон, используемый Microsoft, создан для обеспечения освобождения неуправляемых ресурсов, даже если вы не вызываете Dispose().

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

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

В худшем случае, когда финализатор вызывает Dispose (), XmlWriter уже может быть удален, и вы получите исключение. Так что лучше не финализатор.

...