Какие требования у.NET при стандартной сериализации?

Какие требования у .NET при стандартной сериализации?
  • Вопрос задан
  • 2575 просмотров
Решения вопроса 1
AlekseyNemiro
@AlekseyNemiro
ответ помог - отметь решением, нет - будет удалён
Чтобы класс можно было сериализовать, необходимо пометить его атрибутом [Serializable].
[Serializable]
public class MyClass 
{
}

Атрибут [Serializable] также должны иметь все типы, которые включены в класс. Если у какого-то из типов не будет этого атрибута, то при попытке выполнить сериализацию, возникнет исключение. Это минимум, что необходимо.

Для двоичной сериализации используется класс BinaryFormatter.
// данные, которые будем сериализовать
var data = new List<int> { 1, 2, 3 };

// выполняем сериализацию 
// в MemoryStream (можно в любой Stream)
var bf = new BinaryFormatter();
var m = new MemoryStream();
bf.Serialize(m, data);
            
// курсор потока переводим в начало, т.к. мы работали с потоком выше
// если открывать новый поток, то это делать не обязательно
m.Position = 0;
// выполняем десериализацию данных из MemoryStream
var result = (List<int>)bf.Deserialize(m);

// выводим результат в консоль
result.ForEach(itm => Console.WriteLine(itm));


Если в объекте попадется тип, который не помечен атрибутом [Serializable], то можно реализовать в классе интерфейс ISerializable. Либо сделать для этого типа отдельный класс, реализующий интерфейс ISerializable. При этом, не забывая про атрибут [Serializable], который обязательно должен присутствовать.

При реализации интерфейса ISerializable, в классе нужно определит метод GetObjectData, который будет подготавливать данные для сериализации. А также реализовать перегрузку конструктора для принятия сериализованных данных.
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
  if (info == null)
  {
    throw new ArgumentNullException("info");
  }
  info.AddValue("Ключ", "Значение");
  info.AddValue("Ключ2", this.ИмяСвойства); 
  // и т.д.
}

// конструктор
protected ИмяКласса(SerializationInfo info, StreamingContext context)
{
  if (info == null)
  {
    throw new ArgumentNullException("info");
  }
  this.Свойство = info.GetValue("Ключ", typeof(типДанных));
  this.ИмяСвойства = (string)info.GetValue("Ключ2", typeof(string));
  // и т.д.
}

Часто спрашивают, как сериализовать Dictionary<TKey, TValue>. На основе всего выше изложенного, можно сделать вот такой класс:
[Serializable]
public class MyDictionary : Dictionary<string, object>, ISerializable
{

  public MyDictionary() { }

  protected MyDictionary(SerializationInfo info, StreamingContext context)
  {
    if (info == null)
    {
      throw new ArgumentNullException("info");
    }
    int count = info.GetInt32("Count"); // получаем число элементов
    for (int i = 0; i < count; i++) // перебираем элементы
    {
      // получаем ключ и значение по индексу элемента
      string key = info.GetString(String.Format("ItemKey{0}", i));
      object value = info.GetValue(String.Format("ItemValue{0}", i), typeof(object));
      // добавляем элемент в себя
      this.Add(key, value);
    }
  }

  public void GetObjectData(SerializationInfo info, StreamingContext context)
  {
    if (info == null)
    {
      throw new ArgumentNullException("info");
    }
    // перебираем все элементы коллекции
    int i = 0;
    foreach (KeyValuePair<string, object> item in this)
    {
      // добавляем отдельно ключ и значение
      info.AddValue(String.Format("ItemKey{0}", i), item.Key, typeof(string));
      info.AddValue(String.Format("ItemValue{0}", i), item.Value);
      i++;
    }
    // запоминаем, сколько всего элементов
    info.AddValue("Count", this.Count);
  }
}

Пример использования:
// выполняем сериализацию коллекции
var data = new MyDictionary();
data.Add("Key", "Value");
data.Add("Key2", "Value2");
data.Add("Key3", 123);

var bf = new BinaryFormatter();
var m = new MemoryStream();
bf.Serialize(m, data);

// выполняем десериализацию
m.Position = 0;
var result = (MyDictionary)bf.Deserialize(m);

// выводим результат
foreach (var item in result)
{
  Console.WriteLine("{0} = {1}", item.Key, item.Value);
}

Посмотреть в .NET Fiddle, как это работает.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы