(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Deserialize в существующие объекты используя стандартный форматер

Источник: habrahabr
mdaemon

Штатная десериализация .net всегда создает граф новых объектов. Это не всегда удобно. 

  • Например если объекты содержат несериализуемые данные, открытые хэндлы и прочее.
  • Объекты не попадающие в сериализацию могут иметь ссылки на зачитываемые объекты и т.п. Особенно это актуально, если ваша сборка используется еще кем то, и вы не можете решить все подобные случаи при помощи правильного дизайна.
  • И в конце концов, ради небольшого Undo полностью пересоздавать объекты нерационально.

Поиск не дал готового ответа. Есть не самые простые решения с использованием protobuf и прочих сторонних сериализаторов, но это не всегда применимо.

Задача в целом несложная, и мое решение не является чем то выдающимся, но с другой стороны, тем кто впервые столкнется с похожей проблемой - будет проще.

Сериализация делается как обычно. Следующие 2 класса решат проблему при десериализации.

    
    [Serializable]
    public class RealObjectHelper : IObjectReference, ISerializable 
    {
        Object m_realObject;
        virtual object getObject(ObjectId id)
        {
            //Этот метод должен возвращать ваш объект,
            return id.GetObject();
        }
        public RealObjectHelper(SerializationInfo info, StreamingContext context)
        {
            ObjectId id = (ObjectId)info.GetValue("ID", typeof(ObjectId));
            m_realObject = getObject(id);
            if(m_realObject == null)
                return;
            Type t = m_realObject.GetType();
            MemberInfo[] members = FormatterServices.GetSerializableMembers(t, context);
            List<MemberInfo> deserializeMembers = new List<MemberInfo>(members.Length);
            List<object> data = new List<object>(members.Length);
            foreach(MemberInfo mi in members)
            {
                Type dataType = null;
                if(mi.MemberType == MemberTypes.Field)
                {
                    FieldInfo fi = mi as FieldInfo;
                    dataType = fi.FieldType;
                } else if(mi.MemberType == MemberTypes.Property){
                    PropertyInfo pi = mi as PropertyInfo;
                    dataType = pi.PropertyType;
                }
                try
                {
                    if(dataType != null){
                        data.Add(info.GetValue(mi.Name, dataType));
                        deserializeMembers.Add(mi);
                    }
                }
                catch (SerializationException)
                {
                    //some fiels are missing, new version, skip this fields
                }
            }
            FormatterServices.PopulateObjectMembers(m_realObject, deserializeMembers.ToArray(), data.ToArray());
        }

        public object GetRealObject( StreamingContext context )
        {
            return m_realObject;
        }
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
        }
    }

    public class RealObjectBinder: SerializationBinder
    {
        String assemVer;
        String typeVer;
        public RealObjectBinder(String asmName, String typeName)
        {
            assemVer = asmName;
            typeVer = typeName;
        }
        public override Type BindToType( String assemblyName, String typeName ) 
        {
            Type typeToDeserialize = null;
            if ( assemblyName.Equals( assemVer ) && typeName.Equals( typeVer ) )
            {
                return typeof(RealObjectHelper);
            }
            typeToDeserialize = Type.GetType( String.Format(  "{0}, {1}", typeName, assemblyName ) );
            return typeToDeserialize;
        }
    }

При десериализации надо установить Binder, который создаст обертку для десериализации в ваш существующий объект.

    BinaryFormatter bf = new BinaryFormatter(null, context);
    bf.Binder = new RealObjectBinder(YourType.Assembly.FullName, YourType.FullName);
    bf.Deserialize(memStream);

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 27.11.2012 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
VMware Horizon 7 Standard : 10 Pack (CCU)
Panda Antivirus Pro - ESD версия - на 1 устройство - (лицензия на 1 год)
Dr.Web Security Space, продление лицензии на 1 год, 1 ПК
Bamboo
CAD Import .NET Professional пользовательская
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
СУБД Oracle "с нуля"
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
Новые материалы
Мир OLAP и Business Intelligence: новости, статьи, обзоры
Работа в Windows и новости компании Microsoft
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
Обсуждения в форумах
Топ рейтинг слотов 2021 года (6)
Среди огромного выбора азартных слотов...
 
Пишу программы на заказ профессионально (3292)
Пишу программы на заказ на языках Pascal (численные методы, списки, деревья, прерывания) под...
 
Отличается ли ДрифтКазино от беттинга? (43)
Друзья, давно заметил, что на Дрифте уже несколько месяцев во всю рекламируется и предлагается...
 
Программы Delphi на заказ (246)
Пишу программы в среде Delphi на заказ http://bddelphi.ucoz.ru/
 
Нормальные казино в 2021 году (14)
После долгих поисков все таки смог найти хорошие игровухи, хотя и ушла куча времени, пока я...
 
 
 



    
rambler's top100 Rambler's Top100