XmlWriter - одноразовый - PullRequest
       30

XmlWriter - одноразовый

2 голосов
/ 14 февраля 2020

У меня проблемы с пониманием работы XmlWriter в C#. Возьмем следующий код, как если бы он был гипотетически использован где-то.

StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = new UTF8Encoding(false);
settings.ConformanceLevel = ConformanceLevel.Document;
settings.Indent = true;

XmlWriter writer = XmlWriter.Create(builder, settings);

// Do stuff

writer.Close();

Поскольку XmlWriter не используется в операторе using, может ли это привести к OutOfMemoryException из-за неправильной его утилизации?

Ответы [ 4 ]

2 голосов
/ 14 февраля 2020

В конечном счете, цель Dispose() в этом случае состоит в том, чтобы позволить XmlWriter принять право собственности на все, что он записывает - например, если вы создаете XmlWriter поверх Stream, вызов Dispose() на XmlWriter может (по умолчанию) flu sh xml Writer , а затем вызов Dispose() в потоке . Это позволяет легко передавать XmlWriter в API, и при этом не нужно передавать им цепочку других объектов, которые они должны располагать по завершении (например, это может быть XmlWriter, говорящий с CompressionStream говорить с SslStream говорить с NetworkStream, et c).

В общий случай , цель Dispose() на окончательном конце - закрыть базовый ресурс (который может быть файлом, сокетом, каналом и т. д. c)

В этом конкретном c случае вы говорите с StringBuilder. Dispose() здесь в основном не работает, так как не является внешним ресурсом . Он просто будет собран G C в любом случае, в будущем. Таким образом, нет: здесь нет проблемы утечки памяти; G C может видеть, что вы делаете.

Итак: в этом случае это не будет иметь функционального значения, но: это хорошая практика, чтобы привыкнуть к этой привычке вызова Dispose() (обычно через using), когда это является частью API, поскольку во многих случаях это действительно, очень важно .

0 голосов
/ 14 февраля 2020

Это может вызвать проблемы с памятью, если в

// Do stuff

возникнет исключение. В этом случае метод Close не будет выполнен. Использование оператора - это синтактический c сахар вокруг блоков try-finally. Он вызывает Dispose в блоке finally даже при наличии исключения

XmlWriter.Dispose вызывает метод Close позади сцены

0 голосов
/ 14 февраля 2020

в соответствии с c# документами. Оператор using гарантирует, что Dispose вызывается, даже если исключение происходит в блоке using. Вы можете достичь того же результата, поместив объект в блок try, а затем вызвав Dispose в блоке finally; на самом деле, именно так оператор using переводится компилятором. Приведенный выше пример кода расширяется до следующего кода во время компиляции (обратите внимание на дополнительные фигурные скобки, чтобы создать ограниченную область видимости для объекта):

        {
            var font1 = new Font("Arial", 10.0f);
            try
            {
                byte charset = font1.GdiCharSet;
            }
            finally
            {
                if (font1 != null)
                    ((IDisposable)font1).Dispose();
            }
        }

и функция close - то же самое. Этот метод вызывает Dispose, указав true, чтобы освободить все ресурсы. Вам не нужно специально вызывать метод Close. Вместо этого убедитесь, что каждый объект Stream правильно расположен. Вы можете объявить объекты Stream внутри блока using (или блока Using в Visual Basi c), чтобы обеспечить удаление потока и всех его ресурсов, или же вы можете явно вызвать метод Dispose.

0 голосов
/ 14 февраля 2020

Хорошо иметь блок using, где он обеспечивает вызов Dispose для любого объекта, который реализует IDisposable.

using (XmlWriter writer = XmlWriter.Create(builder, settings))
{
     //do stuff
}

Метод Dispose для XmlWriter выглядит как

protected virtual void Dispose(bool disposing)
{
    if (this.WriteState != WriteState.Closed)
    {
        try
        {
            this.Close();
        }
        catch
        {
        }
    }
}
...