Статьи

Сериализация Windows Phone 7: двоичная сериализация

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