#c# #.net #visual-studio-2010
#c# #.net #visual-studio-2010
Вопрос:
У меня следующая проблема: когда я запускаю свое приложение, настройки загружаются из файла, поэтому десериализуются, когда это происходит, я получаю следующую ошибку:
{"End of Stream encountered before parsing was completed."} System.Exception {System.Runtime.Serialization.SerializationException}
Код сериализации:
using(FileStream write = new FileStream(SETTINGSPATH,FileMode.Create,FileAccess.Write)
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(write,settings);
}
Метод десериализации:
using (FileStream read = new FileStream(SETTINGSPATH,FileMode.Open,FileAccess.Read))
{
BinaryFormatter formatter = new BinaryFormatter();
read.Position = 0;
settings = (Settings)formatter.Deserialize(read); // settings is declared as Settings object
}
Класс настроек:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
namespace Serie_Counter.Overkoepelend
{
public delegate void SelectedMoveOptionChanged(AutoMoveOption selectedOption, int checkInterval = 30 );
public delegate void EnableAutoMoveChanged(bool EnableAutoMove);
[Serializable]
public class Settings
{
private string serieListSavePath;
private bool autoStart;
private bool enableRember;
private bool closeWithMainForm;
private int warningDelay;
// moving options
private bool enableAutoMove;
private string rootFolder;
private int checkInterval;
private AutoMoveOption selectedMoveOption;
public event SelectedMoveOptionChanged selectedMoveOptionChanged;
public event EnableAutoMoveChanged enableAutoMoveChanged;
#region Properties
public string SerieListSavePath
{
get
{
return serieListSavePath;
}
set
{
serieListSavePath = value;
}
}
public bool AutoStart
{
get
{
return autoStart;
}
set
{
autoStart = value;
}
}
public bool EnableRember
{
get
{
return enableRember;
}
set
{
enableRember = value;
}
}
public bool CloseWithMainForm
{
get
{
return closeWithMainForm;
}
set
{
closeWithMainForm = value;
}
}
public int WarningDelay
{
get
{
return warningDelay;
}
set
{
warningDelay = value;
}
}
public bool EnableAutoMove
{
get
{
return enableAutoMove;
}
set
{
enableAutoMove = value;
if (enableAutoMove != null) enableAutoMoveChanged(value);
}
}
public string RootFolder
{
get
{
return rootFolder;
}
set
{
rootFolder = value;
}
}
public int CheckInterval
{
get
{
return checkInterval;
}
set
{
checkInterval = value;
}
}
public AutoMoveOption SelectedMoveOption
{
get
{
return selectedMoveOption;
}
set
{
selectedMoveOption = value;
selectedMoveOptionChanged(value, checkInterval);
}
}
#endregion
public Settings(string serieListSavePath)
{
this.serieListSavePath = serieListSavePath;
}
public Settings()
{
this.serieListSavePath = "series.xml";
warningDelay = -1;
}
[OnDeserialized]
private void SetValuesOnDeserialized(StreamingContext context)
{
selectedMoveOptionChanged = null;
enableAutoMoveChanged = null;
}
Кто-нибудь знает, почему это происходит?
Если вам нужна дополнительная информация или код, пожалуйста, проверьте http://seriescounter.codeplex.com /
Приветствует Томаса
РЕДАКТИРОВАТЬ: Может ли проблема заключаться в том, что десериализация завершается неудачно, потому что я сериализую события в? Я только что протестировал это, убедившись, что события равны нулю при сериализации. и до сих пор ошибка больше не повторялась.
http://seriescounter.codeplex.com/SourceControl/changeset/changes/12646
Комментарии:
1. Вы проверили, существует ли файл и не поврежден ли он?
2. Если вы просто сохраняете настройки, то эмпирическое правило заключается в использовании читаемого формата, такого как XML, для сохранения настроек.
3. Пожалуйста, опубликуйте код, который вы используете для сериализации, и сохраните настройки. Это нелегко найти в ссылке на codeplex, которую вы опубликовали. Я подозреваю, что может отсутствовать
Flush
. Кроме того, вы неправильно запускаете своеenableAutoMoveChanged
событие. Вы должны сначала скопировать событие в локальную переменную,var ev=enableAutoMoveChanged;
затем проверить,ev
не равно ли оно null, затем запустить егоev(value);
4. Я проверяю, существует ли файл, код сериализации: <code> используя(FileStream write = new FileStream(SETTINGSPATH,FileMode. Создать,FileAccess. Запись)) { BinaryFormatter formatter = new BinaryFormatter(); форматировщик. Сериализовать (запись, настройки); } </code> может быть, у меня ошибка, потому что я сериализую события, чтобы?
5. Я бы сериализовал в читаемый формат (xml / json) и посмотрел, что не так с файлом настроек
Ответ №1:
Ваша проблема в наборе изменений 12594, вы добавили событие checkIntervalChanged в класс Settings. Это добавило в класс невидимое поле, которое также сериализуется. Но теперь у вас проблема с настройкой файлов, которые были сохранены с предыдущей версией, данные сериализации не содержат этого поля, результатом является исключение.
Вы можете спасти его следующим образом:
[Serializable]
public class Settings {
[NonSerialized]
private CheckIntervalChanged checkIntervalChangedBacking;
public event CheckIntervalChanged CheckIntervalChanged {
add { checkIntervalChangedBacking = value; }
remove { checkIntervalChangedBacking -= value; }
}
// etc..
}
Атрибут [Несериализованный] теперь гарантирует, что резервное поле не будет сериализовано. Вы все равно никогда не захотите сериализовать события.
В общем, вам нужно быть осторожным с двоичной сериализацией, с управлением версиями сложно иметь дело. Добавление поля может и мгновенно превратит любые сохраненные данные в мусор. Есть хорошие подсказки в «версий сериализациюраздел» в библиотеке MSDN.
Комментарии:
1. Добавленные поля в класс не должны влиять на десериализацию из более старой версии, поскольку неизвестные поля будут просто заполнены значениями по умолчанию. Также проще не сериализовывать события, используя спецификатор поля для атрибута, т.е.
[field: NonSerialized]
при объявлении события.2. Я получил ту же ошибку и нашел эту страницу. Однако, как оказалось, моя проблема в том, что я добавил новый класс и забыл добавить атрибут [Serializable] к классу, так что он изначально не был сериализован правильно. Затем, когда он пытается десериализовать, я получил эту ошибку. После добавления атрибута [Serializable] к классу все работает нормально.