(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
Allround Automation PL/SQL Developer - Annual Service Contract - Single user
Panda Mobile Security - ESD версия - на 1 устройство - (лицензия на 1 год)
JIRA Software Commercial (Cloud) Standard 10 Users
ABBYY Lingvo x6 Многоязычная Профессиональная версия, электронный ключ
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 для начинающих. Новости + статьи + обзоры + ссылки
Новые материалы
Все о PHP и даже больше
ЕRP-Форум. Творческие дискуссии о системах автоматизации
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100