(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
Advanced Data Export VCL Suite (with sources) + 1 Year Maintenance
DevExpress / DXperience Subscription
VMware Fusion 10 Pro, ESD
The BAT! Professional - 1 компьютер
WinRAR 5.x 1 лицензия
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
СУБД Oracle "с нуля"
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
Новые материалы
Новые программы для Windows
Новости мира 3D-ускорителей
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100