34 / 21 / 2
Регистрация: 31.03.2009
Сообщений: 362
1

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

19.10.2009, 18:45. Показов 3123. Ответов 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
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.10.2009, 18:45
Ответы с готовыми решениями:

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

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

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

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

7
84 / 83 / 6
Регистрация: 13.07.2009
Сообщений: 107
20.10.2009, 00:14 2
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  [ТС] 3
а конкретно для моего варианта поправки нету? ^_^" я попробую твой вариант, но просто на моей стадии это оч сложно) просто я однажды делал сериализацию с классом содержащий списки, все сделал так же, однако читать нехочет правильно... вернее не читает вобще... сохранять сохраняет, проверил...
0
1922 / 427 / 41
Регистрация: 12.07.2007
Сообщений: 2,062
20.10.2009, 07:42 4
Попробуйте переделать поля в свойства.
Также заменить FileMode.Append на режим создания файла.
1
84 / 83 / 6
Регистрация: 13.07.2009
Сообщений: 107
20.10.2009, 11:38 5
Я еще вчера хотел написать на счет замены FileMode.Append на FileMode.Create, у меня и в примере так, но было уже поздно, спешил успеть выложить готовый проект, вот и забыл.

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

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

Добавлено через 13 минут
и все же как выяснилось этот метод не подходит... даже если установить статичный ключ(всмысле что он не меняется при перезапуске) выдается ошибка десериализации, то что не найден объекв верхнего уровня... есть варианты исправить это или придеться криптовать строки?
0
84 / 83 / 6
Регистрация: 13.07.2009
Сообщений: 107
20.10.2009, 18:22 8
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
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
20.10.2009, 18:22
Помогаю со студенческими работами здесь

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru