Многие из вас, вероятно, заметили, что Windows Phone 7 не поддерживает стандартную двоичную сериализацию (с использованием BinaryFormatter из пространства имен System.Runtime.Serialization), как полная версия .NET Framework, поэтому я решил создать собственное решение для двоичной сериализации и десериализация с использованием классов BinaryWriter и BinaryReader. Этот пост частично описывает мое решение.
Дополнительная информация
Добавление ссылки
Возможно, этот шаг может быть необязательным, если вы решите изменить мой код, но в настоящее время мой подход к двоичной сериализации требует добавления пространства имен System.Runtime.Serialization в проект для создания класса SampleData, описанного ниже. Чтобы добавить ссылку, щелкните правой кнопкой мыши имя проекта и выберите «Добавить ссылку». Выберите пространство имен System.Runtime.Serialization на вкладке .NET (см. Изображение ниже).
Создание примера класса
Я собираюсь использовать почти тот же класс, который я создал для учебника по сериализации DataContract . Чтобы разрешить сериализацию свойств, вы должны применить к ним DataMemberAttribute .
public class SampleData { [DataMember] public string ContentText { get; set; } [DataMember] public List<int> SomeItems { get; set; } public SampleData() { ContentText = "some text"; SomeItems = new List<int>() { 1, 2, 3 }; } }
Создание класса CustomBinarySerializer
Моя цель состояла в том, чтобы сделать двоичную сериализацию и десериализацию похожей на DataContract и XML Serialization , то есть должен быть конструктором, который принимает тип в качестве параметра и два метода WriteObject и ReadObject. По этой причине я создал класс CustomBinarySerializer. В настоящее время, это ручка класса только строка и List <Int> тип (для моего класса SampleData описаны выше). Не стесняйтесь добавлять другие обработанные типы и, возможно, изменять этот класс, создавая методы расширения для этих типов, как описано в этомстатья. Частично реализованная версия CustomBinarySerializer выглядит следующим образом (обратите внимание, что этот класс сериализует и десериализует только те свойства, которые отмечены с помощью DataMemberAttribute ):
public class CustomBinarySerializer { private List<PropertyInfo> serializableProperties = new List<PropertyInfo>(); private Type serializableObjectType; public CustomBinarySerializer(Type objectType) { serializableObjectType = objectType; serializableProperties = GetMarkedProperties(objectType); } private List<PropertyInfo> GetMarkedProperties(Type type) { return (from property in type.GetProperties() where property.GetCustomAttributes(true) .Where((x) => x is System.Runtime.Serialization.DataMemberAttribute).Count() > 0 select property ).ToList(); } #region Write public void WriteObject(Stream stream, object graph) { if (stream == null || graph == null) return; BinaryWriter bw = new BinaryWriter(stream); foreach (PropertyInfo pi in serializableProperties) { var value = pi.GetValue(graph, null); if (pi.PropertyType == typeof(string)) { bw.Write(value as string ?? string.Empty); } else if (pi.PropertyType == typeof(List<int>)) { WriteIntegerList(bw, value as List<int>); } } } private void WriteIntegerList(BinaryWriter bw, List<int> list) { if (list == null || !list.Any()) { bw.Write(0); } else { bw.Write(list.Count); list.ForEach(x => bw.Write(x)); } } #endregion Write #region Read public object ReadObject(Stream stream) { if (stream == null) return null; BinaryReader br = new BinaryReader(stream); object deserializedObject = Activator.CreateInstance(serializableObjectType); foreach (PropertyInfo pi in serializableProperties) { if (pi.PropertyType == typeof(string)) { pi.SetValue(deserializedObject, br.ReadString(), null); } else if (pi.PropertyType == typeof(List<int>)) { pi.SetValue(deserializedObject, ReadIntegerList(br), null); } } return deserializedObject; } private List<int> ReadIntegerList(BinaryReader br) { List<int> list = new List<int>(); int count = br.ReadInt32(); int index = count; while(index > 0){ list.Add(br.ReadInt32()); index--; } return list; } #endregion Read }
Сериализация
Для сериализации объекта необходимо создать экземпляр класса CustomBinarySerializer (передавая тип сериализованного объекта в качестве входного параметра), а затем записать сериализованные данные в объект потока с помощью метода WriteObject, который принимает поток и объект для сериализации.
public static void Serialize(Stream streamObject, object objForSerialization) { if (objForSerialization == null || streamObject == null) return; CustomBinarySerializer ser = new CustomBinarySerializer(objForSerialization.GetType()); ser.WriteObject(streamObject, objForSerialization); }
Десериализация
Чтобы десериализовать ваш объект, вам нужно снова создать экземпляр класса CustomBinarySerializer (на основе типа сериализованного объекта), а затем прочитать сериализованные данные, используя метод ReadObject, который принимает экземпляр класса Stream в качестве параметра.
public static object Deserialize(Stream streamObject, Type serializedObjectType) { if (serializedObjectType == null || streamObject == null) return null; CustomBinarySerializer ser = new CustomBinarySerializer(serializedObjectType); return ser.ReadObject(streamObject); }
тестирование
Вы можете использовать метод ниже для проверки двоичной сериализации и десериализации. Объект SampleData после десериализации должен быть точно таким же, как объект до сериализации.
public static void Test() { // serialization MemoryStream ms = new MemoryStream(); BinarySerializationHelper.Serialize(ms, new SampleData()); ms.Position = 0; // deserialization var sampleData = BinarySerializationHelper.Deserialize(ms, typeof(SampleData)); ms.Close(); }
Вот как выглядит сериализованный объект SampleData во время отладки:
Источник:
http://www.eugenedotnet.com/2010/12/windows-phone-7-serialization-binary-serialization/