Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.76/21: Рейтинг темы: голосов - 21, средняя оценка - 4.76
34 / 21 / 2
Регистрация: 31.03.2009
Сообщений: 362

Ошибка сериализации

19.10.2009, 18:45. Показов 4138. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
есть класс, в котором 2 массива List<string>, есть listView, я добавляю в него эл-ты и одновременно добавляют элементы в массив того класса, затем сериализую и сохраняю, но при загрузке получается так что массивы имеют значение null
код класса:
C#
1
2
3
4
5
6
[Serializable]
    public class Subjects
    {
        public List<string> predmet = new List<string>();
        public List<string> hours = new List<string>();
    }
код формы:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Subjects subj = new Subjects();
        private void add_subject_Click(object sender, EventArgs e)
        {
            try
            {
                int i = Convert.ToInt32(hours.Text);
            }
            catch
            {
                MessageBox.Show("Неверный формат часов.\n\rВведите кол-во часов предмета в семестре.");
                return;
            }
            subj.predmet.Add(subject_name.Text);
            subj.hours.Add(hours.Text);
            ClearList();
            FillSubjectsList();
            save_subjects();
        }
        public void FillSubjectsList()
        {
            
            //item.SubItems.Add(subject_name.Text);
            //item.SubItems.Add(hours.Text);
            //subjects_list.Items.Add(item);
            if (subj.predmet.Count >= 1 || subj.hours.Count >= 1) //тут ошибка, не присвоена ссылка на объект, а точнее массивы равны null
            {
                for (int i = 0; i < subj.hours.Count; i++)
                {
                    ListViewItem item = new ListViewItem();
                    item.SubItems.Add(subj.predmet[i]);
                    item.SubItems.Add(subj.hours[i]);
                    subjects_list.Items.Add(item);
                }
                
            }
        }
        public void save_subjects()
        {
            FileStream fs = new FileStream(@"data.dat", FileMode.Append, FileAccess.Write);
 
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, subj);
            fs.Close();
        }
        public void load_subjects()
        {
            FileStream fs = new FileStream(@"data.dat", FileMode.Open, FileAccess.Read);
 
            BinaryFormatter bf = new BinaryFormatter();
            subj = (Subjects)bf.Deserialize(fs);
            fs.Close();
            ClearList();
            FillSubjectsList();
        }
        public void ClearList()
        {
            subjects_list.Items.Clear();
            
        }
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.10.2009, 18:45
Ответы с готовыми решениями:

Ошибка сериализации
Здравствуйте! Приложение выбрасывает исключение и я не могу понять почему:В месте: lock (sLock) { bmp =...

Ошибка сериализации/десериализации
Доброго времени суток. Пишу программу для передачи информации о компьютере по сети. Имеются 2 приложения (сейчас обы Windows Form, в...

Ошибка при сериализации
случилось у меня такая ситуация, что есть у меня класс, который я успешно сериализовал, после изменений в проекте (без изменений этого...

7
84 / 83 / 6
Регистрация: 13.07.2009
Сообщений: 107
20.10.2009, 00:14
LordXaosa, для начала хочу сделать несколько замечаний.
1) List<T> - это НЕ массив, это динамический generic список. Его можно проиндексировать как массив, но называть его массивом не правильно!
2) Раз ты добавляешь элементы попарно, то у тебя, получается, лучшим способом хранения будет класс Dictionary<TKey, TValue>. Но если предположить, что позднее может добавится еще одно или более полей, то лучше вынести все поля в один отдельный класс, а уж потом его экземпляр добавлять в список List<T>.
3) Если для списка объектов предусматриваются дополнительные действия кроме стандартных, например сохранение и восстановление, то лучше выносить этот список в отдельный класс обертку вокруг стандартного контейнера. Таким образом это получится независимый объект, который знает что содержит и имеет все методы, неообходимые для обработки своих данных. Такой объект должен защищать свои данные от внешнего вмешательства и позволять делать с ними только то, что предусмотрел разработчик.
4) Я так и не понял зачем при каждом добавление пары значений, ты очишаешь содержимое визуального ListView объекта и перезаполняешь его всеми значениями заново.

Я мало работал с WinForms приложениями, что бы привести код близкий к идеальному, но я бы решил твою задачу приблизительно так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
namespace Example
{
  public partial class Form1:Form
  {
    //экземпляр коллекции объектов
    private Subjects list;
    public Form1()
    {
      InitializeComponent();
      list=new Subjects();
    }
 
    private void saveBtn_Click(object sender,EventArgs e)
    {
      Subjects.Save("subjects.dat",list);
    }
 
    private void loadBtn_Click(object sender,EventArgs e)
    {
      Subjects.Load("subjects.dat",list);
    }
 
    private void addBtn_Click(object sender,EventArgs e)
    {
      list.Add(eName.Text,eHours.Text);
      eName.Text="";
      eHours.Text="";
      eName.Focus();
    }
 
    //класс для элемента коллекции
    [Serializable]
    public class Subject
    {
      private string predmet;
      public string Predmet
      {
        get { return predmet; }
      }
 
      public string hours;
      public string Hours
      {
        get { return hours; }
      }
 
      public Subject(string predmet,string hours)
      {
        this.predmet=predmet;
        this.hours=hours;
      }
    }
 
    //коллекция однотипных элементов
    //поддерживает добавление элемента, сохранение всего списка в файле и его последующее восстановление
    [Serializable]
    public class Subjects:IDeserializationCallback
    {
      private List<Subject> sList=new List<Subject>();
      public List<Subject> SList
      {
        get { return sList; }
      }
 
      public void Add(string predmet,string hours)
      {
        sList.Add(new Subject(predmet,hours));
 
        //ListViewItem item=new ListViewItem();
        //item.SubItems.Add(predmet);
        //item.SubItems.Add(hours);
        //Program.Form.subjects_list.Items.Add(item);
 
        Program.Form.subjects_list.Items.Add(new ListViewItem(new string[] { predmet,hours }));
      }
 
      public static void Save(string fileName,Subjects list)
      {
        FileStream fs=new FileStream(fileName,FileMode.Create);
        BinaryFormatter bf=new BinaryFormatter();
        bf.Serialize(fs,list);
        fs.Close();
      }
 
      public static bool Load(string fileName,Subjects list)
      {
        try
        {
          FileStream fs=new FileStream(fileName,FileMode.Open);
          BinaryFormatter bf=new BinaryFormatter();
          list=(Subjects) bf.Deserialize(fs);
          fs.Close();
          return true;
        }
        catch { return false; }
      }
 
      #region IDeserializationCallback Members
 
      //реализация интерфейса IDeserializationCallback - вызывается по окончании процесса десериализации
      public void OnDeserialization(object sender)
      {
        Program.Form.subjects_list.Clear();
        for (int i=0;i<sList.Count;i++)
          Program.Form.subjects_list.Items.Add(new ListViewItem(new string[] { sList[i].Predmet,sList[i].Hours }));
      }
 
      #endregion
    }
  }
}
Для того, что бы класс Subjects мог обращаться к объекту ListView формы, пришлось немного видоизменить файл program.cs:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace Example
{
  static class Program
  {
    //эти дла поля нужны, что бы получить к ним доступ из внешних классов
    private static Form1 form;
    public static Form1 Form { get { return form; } }
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      form=new Form1();
      Application.Run(form);
    }
  }
}
Полный проект для MS Visual Studio 2008 смотри во вложении.
Вложения
Тип файла: rar Example.rar (38.6 Кб, 14 просмотров)
1
34 / 21 / 2
Регистрация: 31.03.2009
Сообщений: 362
20.10.2009, 00:27  [ТС]
а конкретно для моего варианта поправки нету? ^_^" я попробую твой вариант, но просто на моей стадии это оч сложно) просто я однажды делал сериализацию с классом содержащий списки, все сделал так же, однако читать нехочет правильно... вернее не читает вобще... сохранять сохраняет, проверил...
0
1923 / 428 / 41
Регистрация: 12.07.2007
Сообщений: 2,062
20.10.2009, 07:42
Попробуйте переделать поля в свойства.
Также заменить FileMode.Append на режим создания файла.
1
84 / 83 / 6
Регистрация: 13.07.2009
Сообщений: 107
20.10.2009, 11:38
Я еще вчера хотел написать на счет замены FileMode.Append на FileMode.Create, у меня и в примере так, но было уже поздно, спешил успеть выложить готовый проект, вот и забыл.

Сложно сказать, почему еще могли возникнуть проблемы с десериализацией. В C# это в большинстве случаев автоматический процесс требующий всего несколько строк кода и с которым у меня никогда не возникало проблнем :-\.
На крайний случай можешь выложить свой проект - я под отладкой посмотрю, что не так.
1
34 / 21 / 2
Регистрация: 31.03.2009
Сообщений: 362
20.10.2009, 11:58  [ТС]
да действительно, надо было заменить с Append на Create... тото я смотрел что файл после некоторых сохранений огромным становился)
0
34 / 21 / 2
Регистрация: 31.03.2009
Сообщений: 362
20.10.2009, 16:20  [ТС]
а не подскажете, как можно класс сначало закриптовать а потом сирелизовать? просто при сериализации можно прочесть строки к примеру, а надо что бы они были криптованы, как такое можно сделать? есть вариант записывать в класс уже криптованые, тоесть при вводе криптовать, забивать в список... потом при десериализации их раскриптовывать... но както это геморно... есть чтото проще?

Добавлено через 25 минут
прошу прощения, разобрался уже, методом CryptoStream решил задачу, вот ссылка на решение:
http://stackoverflow.com/quest... m-a-stream

Добавлено через 13 минут
и все же как выяснилось этот метод не подходит... даже если установить статичный ключ(всмысле что он не меняется при перезапуске) выдается ошибка десериализации, то что не найден объекв верхнего уровня... есть варианты исправить это или придеться криптовать строки?
0
84 / 83 / 6
Регистрация: 13.07.2009
Сообщений: 107
20.10.2009, 18:22
LordXaosa, C# позволяет управлять процессом сериализации/десериализации.
Например, класс содержит вычисляемые поля и в целях экономии места нету смысла эти поля так же сохранять в файл - эти поля можно пометить атрибутом игнорирования (у каждого форматера свой, у BinaryFormatter - [NonSerialized]). А при восстановлении эти поля можно просто вычислить единожды для каждого экземпляра снова.
Для такой задачи достаточно унаследовать классом интерфейс IDeserializationCallback и определить его функцию
C#
1
public void OnDeserialization(object sender)
В момент, когда эта функция получает управление, все значимые поля уже содержат значения из файла и к ним можно спокойно обращаться. Пример использования этого интерфейса я дал в своем прошлом проекте .

Для задач, когда нужно перед записью в файл изменить значения некоторых значений (например зашифровать), существует другой интерфейс - ISerializable и две его функции:
C#
1
2
3
public virtual void GetObjectData(SerializationInfo info,  StreamingContext context) {}
// The following constructor is for deserialization
protected ShoppingCartItem(SerializationInfo info,  StreamingContext context) {}
Вот маленький шаблонный пример как ими воспользоваться:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;
 
namespace CustomSerialization
{
  class Program
  {
    [Serializable]
    public class SomeClass:ISerializable
    {
      [NonSerialized]
      public string secret1,secret2;
      public string open1,open2;
 
      public SomeClass(string secret1,string secret2,string open1,string open2)
      {
        this.secret1=secret1;
        this.secret2=secret2;
        this.open1=open1;
        this.open2=open2;
      }
 
      private string CryptF(string s)
      {
        //тут можно вызвать какой то метод шифрования
        //для простоты я возвращу туже строку
        return s;
      }
 
      private string DecryptF(string s)
      {
        //тут можно вызвать какой то метод дешифрования
        //для простоты я возвращу туже строку
        return s;
      }
 
      #region ISerializable Members
        private SomeClass(SerializationInfo info,StreamingContext context)
        {
          //считываем все поля, но те которые нужно, предварительно "расшифровываем"
          secret1=DecryptF(info.GetString("Some crypted secret1"));
          secret2=DecryptF(info.GetString("Some crypted secret2"));
          open1=info.GetString("public1");
          open2=info.GetString("public2");
        }
 
        public void GetObjectData(SerializationInfo info,StreamingContext context)
        {
          //добавлять нужно все поля, но те которые нужно, передаются в "зашифрованном" виде
          //в качестве идентификаторов можно использовать любой текст
          info.AddValue("Some crypted secret1",CryptF(secret1));
          info.AddValue("Some crypted secret2",CryptF(secret2));
          info.AddValue("public1",open1);
          info.AddValue("public2",open2);
        }
      #endregion
    }
 
    static void Main(string[] args)
    {
      SomeClass a=new SomeClass("top secret1","top secret2","some public text1",
        "some public text2");
      
      //serialization
      BinaryFormatter bf=new BinaryFormatter();
      FileStream fs=new FileStream("data.bin",FileMode.Create);
      bf.Serialize(fs,a);
      fs.Close();
 
      //deserialization
      fs=new FileStream("data.bin",FileMode.Open);
      SomeClass b=(SomeClass)bf.Deserialize(fs);
 
      Console.WriteLine("{0}; {1}; {2}; {3}",b.secret1,b.secret2,b.open1,b.open2);
      Console.ReadKey();
    }
  }
}
Для класса BinaryFormatter есть еще возможность назначить специальными атрибутами функции обработчики событий начала/окончания сериализации/десериализации...

Вообще-то тут можно много говорить по поводу способов управления процессом сериализации/десериализации, но зачем повторять то, что давно уже написано ?
Можно покопать по этому поводу MSDN или вот [] книгу, раздел 5, глава 3 (а можно и первые 2 тоже ). Я изучал эту тему именно по этой книге.

С классом CryptoStream не сталкивался, ничего подсказать не могу. Может завтра поковыряюсь с ним.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
20.10.2009, 18:22
Помогаю со студенческими работами здесь

Ошибка при сериализации
При компиляции вылетает такая ошибка: Cannot create and instance of the abstract class or interface &quot;System.Xml.XmlWriter&quot;. ...

Ошибка при сериализации от клиента серверу
Передаём данные между сервером и клиентом, при первой сериализации от клиента к серверу - всё гладко, а обратно выбивает ошибку! Самое...

Ошибка при сериализации класса AL7_Class_ExtFileInfo
Здравствуйте. Есть 2 класса. using System; using System.IO; namespace DH_Launcher { public class...

Ошибка InvalidOperationException при Xml сериализации
Здравствуйте! У меня возникла проблема при xml сериализации. Суть проблемы такова, я хочу сохранить список List&lt;myReference&gt; в...

Возникла ошибка при отражении типа во время XML сериализации
В строке using (Stream Read = File.Create(FileName)) { FilialList = new...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru