Сериализация XML без удаления

       using (var file_stream = File.Create("users.xml"))
        {
            var serializer = new XmlSerializer(typeof(PasswordManager));
            serializer.Serialize(file_stream, this);
            file_stream.Close();
        }

Использование приведенного выше кода работает отлично. Однако, когда я сокращаю его до:

          var serializer = new XmlSerializer(typeof(PasswordManager));
          serializer.Serialize(File.Create("users.xml"), this);

Я получаю следующее исключение, когда пытаюсь десериализовать файл users.xml в том же тесте: Процесс не может получить доступ к файлу «users.xml», поскольку он используется другим процессом.

Причина, по-видимому, в том, что метод File.Create возвращает открытый FileStream, который я не могу закрыть, поскольку не держу ссылку на него.

Мой плохой, или Майкрософт? ;-)


person Dabblernl    schedule 17.05.2009    source источник
comment
Здесь есть основная концепция, которую вы упускаете (что легко сделать) — прочитайте об использовании объектов, использующих интерфейс iDisposable.   -  person overslacked    schedule 18.05.2009


Ответы (4)


Проблема в том, что во втором примере вы открываете дескриптор файла, от которого никогда не избавляетесь, поэтому при втором вызове вашего метода он вызовет описываемое вами исключение. Первый фрагмент является предпочтительным способом (вы можете удалить бит file_stream.Close() - он будет автоматически вызываться Stream.Dispose()).

person Darin Dimitrov    schedule 17.05.2009

Вы должны сериализовать в блоке try finally, чтобы убедиться, что файл закрыт/удален независимо от успеха или неудачи. Вот что делает для вас ключевое слово using.

var serializer = new XmlSerializer(typeof(PasswordManager));
var fs = File.Create("users.xml");
try { serializer.Serialize(fs,this); }
finally { fs.Close(); }
person anonymous    schedule 29.06.2009

Если бы у вас не было оператора «using», но вы сохранили закрытие, все было бы в порядке.

[Редактировать: добавлена ​​попытка... наконец, спасибо, спасибо]

var serializer = new XmlSerializer(typeof(PasswordManager));
FileStream fs;
try
{
    fs = File.Create("users.xml");
    serializer.Serialize(fs, this);
}
finally
{
    fs.Close(); // or fs.Dispose()
}

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

person Nader Shirazie    schedule 20.06.2009
comment
не забудьте попробовать... наконец! - person Cheeso; 29.06.2009

File.Create следует поместить за пределы блока try, как показано в моем предыдущем ответе. Если вы поместите его в блок try, вам нужно проверить fs на наличие нулевой ссылки перед закрытием. Ниже показан исправленный код, но мой первый ответ намного лучше, так как вы можете избежать этой проверки.

serializer = new XmlSerializer(typeof(PasswordManager));
FileStream fs;
try
{
    fs = File.Create("users.xml");
    serializer.Serialize(fs, this);
}
finally
{
    if (fs != null)  // in case File.Create fails
        fs.Close(); // or fs.Dispose()
}
person anonymous    schedule 29.06.2009