Многие из вас, вероятно, заметили, что 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/