ritnet.ru

5 Октябрь 2008

Часть 1. Интерфейс ISeflSerializable

Рубрика: Новости — admin @ 2:12

Разрабатывая распределённое приложение неизбежно сталкиваешься с проблемой передачи разнородных данных между элементами программы. Если данных немного (например массив из 10 000 элементов), особых затруднений не возникает. Однако, с ростом объема скорость взаимодействия между клиентским и серверным приложением стремительно падает.

Сериализация, «встроенная» в .net является его слабым местом. Всего существует три специализированных класса. Первые два, XmlSerializer и SoapFormatter, преобразуют объект в строку в формате Xml. Двоичный образ объекта можно получить, используя BinaryFormatter. Все эти классы характеризуются небыстрой работой и большим объемом избыточных данных в выходной последовательности.

Таким образом, если встаёт необходимость передать большой объем данных, надо искать другое решение. Я создал специализированный интерфейс ISelfSerializable:

    /// <summary>
    /// Интерфейс, определяющий методы, позволяющие объекту самостоятельно сериализовываться в поток и восстанавливаться из него.
    /// </summary>
    public interface ISelfSerializable
    {
        /// <summary>
        /// Сериализует объект в поток байт.
        /// </summary>
        /// <param name="writer">BinaryWriter используемый для записи в поток.</param>
        void Serialize(BinaryWriter writer);
        /// <summary>
        /// Загружает поля объекта из потока данных.
        /// </summary>
        /// <param name="reader">BinaryReader используемый для чтения из потока.</param>
        void Deserialize(BinaryReader reader);
    }

Каждый объект, который будет поддерживать «родную» сериализацию, должен его реализовывать. Делается это примерно так:

    public class A : ISelfSerializable
    {
        public int ID;
        public string Value;

        public A()
        {

        }

        public A(int id, string value)
        {
            ID = id;
            Value = value;
        }

        public void Serialize(BinaryWriter writer)
        {
            writer.Write(ID);
            writer.Write(Value);
        }

        public void Deserialize(BinaryReader reader)
        {
            ID = reader.ReadInt32();
            Value = reader.ReadString();
        }
    }

А теперь собственно то, ради чего все это задумывалось – вспомогательный класс, позволяющий быстро и безболезненно сериализовывать коллекции объектов:

    /// <summary>
    /// Класс обеспечивает сериализацию списка однотипных объектов в поток, и восстановление списка из потока.
    /// </summary>
    public static class SerializationHelper
    {
        /// <summary>
        /// Сериализует перечесление элементов, реализующих ISelfSerializable в массив байт.
        /// </summary>
        /// <param name="items">Перечисление элементов.</param>
        /// <returns>Сериализованные данные.</returns>
        /// <remarks>Информация о количестве элементов записывается в первых 4 байтах.</remarks>
        public static byte[] Serialize(IEnumerable<ISelfSerializable> items)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                Serialize(items, ms);
                return ms.ToArray();
            }
        }

        /// <summary>
        /// Сериализует перечесление элементов, реализующих ISelfSerializable в поток.
        /// </summary>
        /// <param name="items">Перечисление элементов.</param>
        /// <param name="output">Поток, в который необходимо сериализовать данные.</param>
        /// <remarks>Информация о количестве элементов записывается в первых 4 байтах.</remarks>
        public static void Serialize(IEnumerable<ISelfSerializable> items, Stream output)
        {
            if (items == null || output == null)
                throw new ArgumentNullException(items == null ? "items" : "output");

            BinaryWriter writer = new BinaryWriter(output);
            writer.Write(items.Count());
            foreach (ISelfSerializable item in items)
            {
                item.Serialize(writer);
            }
        }

        /// <summary>
        /// Восстанавливает элементы. Для корректного использования этого метода необходимо, чтобы информация о количестве элементов была записана перед данными.
        /// </summary>
        /// <typeparam name="ObjectType">Тип сериализуемого объекта, должен реализовывать ISelfSerializable.</typeparam>
        /// <param name="data">Сериализованные данные.</param>
        /// <returns>Список восстановленных элементов.</returns>
        public static List<ObjectType> Deserialize<ObjectType>(byte[] data) where ObjectType : ISelfSerializable, new()
        {
            if (data == null)
                throw new ArgumentNullException("data");

            using (MemoryStream ms = new MemoryStream(data))
            {
                return Deserialize<ObjectType>(ms);
            }
        }

        /// <summary>
        /// Восстанавливает элементы. Для корректного использования этого метода необходимо, чтобы информация о количестве элементов была записана перед данными.
        /// </summary>
        /// <typeparam name="ObjectType">Тип сериализуемого объекта, должен реализовывать ISelfSerializable.</typeparam>
        /// <param name="input">Поток сериализованных данных.</param>
        /// <returns>Список восстановленных элементов.</returns>
        /// <remarks>Позиция в потоке должна стоять перед данными, включая информацию об их количестве.</remarks>
        public static List<ObjectType> Deserialize<ObjectType>(Stream input) where ObjectType : ISelfSerializable, new()
        {
            if (input == null)
                throw new ArgumentNullException("input");

            BinaryReader reader = new BinaryReader(input);
            int count = reader.ReadInt32();
            List<ObjectType> items = new List<ObjectType>(count);
            for (int i = 0; i < count; i++)
            {
                ObjectType item = new ObjectType();
                item.Deserialize(reader);
                items.Add(item);
            }
            return items;
        }
    }

Вторая часть: Сериализация произвольных объектов.

Комментариев нет

Комментариев нет.

RSS-лента комментариев к этой записи.

Извините, обсуждение на данный момент закрыто.

Сайт работает на WordPress