Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Десериализовать себя? А так законно? 
:(
    Опции темы
jonie
Дата 2.8.2008, 22:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 22
Всего: 118



тут была чушь.


вопрос пусть такой будет: а как десериализовать самого себя (вариант с почленным присвоенимем не особо инетересен, мб есть что-нибудь вроде рефлексии...)?

Это сообщение отредактировал(а) jonie - 2.8.2008, 22:59


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
mihryak
Дата 3.8.2008, 00:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



десериализовать из чего?
а в целом, можно и рефлексию задействовать
например, через статический фабричный метод у объекта или стандартный десериализующий конструктор

вот, набросал пример с бинарной сериализацией класса, который через рефлексию складывает при сериализации и забирает при десериализации через десериализующий конструктор свои приватные поля
Код

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;

namespace SerializationTest
{
    class Program
    {
        [Serializable]
        public class Test : ISerializable
        {
            private const BindingFlags FieldBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;

            private readonly int intValue;
            private readonly string stringValue;

            public Test(int intValue, string stringValue)
            {
                this.intValue = intValue;
                this.stringValue = stringValue;
            }

            public int IntValue
            {
                get { return intValue; }
            }

            public string StringValue
            {
                get { return stringValue; }
            }

            public override string ToString()
            {
                return String.Format("IntValue = [{0}], StringValue = [{1}]", intValue, stringValue);
            }

            #region ISerializable Members

            void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
            {
                foreach (FieldInfo fieldInfo in GetType().GetFields(FieldBindingFlags))
                {
                    info.AddValue(fieldInfo.Name, fieldInfo.GetValue(this));
                }
            }

            #endregion

            [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
            private Test(SerializationInfo info, StreamingContext context)
            {
                foreach (SerializationEntry serializationEntry in info)
                {
                    GetType().GetField(serializationEntry.Name, FieldBindingFlags).SetValue(this, serializationEntry.Value);
                }
            }

        }

        static void Main()
        {
            Test test = new Test(5, "string");
            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream stream = new MemoryStream())
            {
                formatter.Serialize(stream, test);
                stream.Position = 0;
                test = (Test) formatter.Deserialize(stream);
            }
            Console.WriteLine(test);
            Console.ReadKey();
        }
    }
}

PM MAIL ICQ   Вверх
jonie
Дата 3.8.2008, 00:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 22
Всего: 118



до этого я дошел... 
в общем доопишу ситуацию (чего мне бы хотелось).

итак. пусть у нас есть базовый класс :
Код

class Base {
 public virtual void Serialize() {...}
 public virtual void Deserialize() {...}
}

пусть он умеет сериализоваться\десерелиазоваться кудато.

теперь я хочу чтобы и все его потомки сереализовались и десериализовались, да так, чтобы они об этом даже "не знали". Т.е. без внесения в них какого-то кода вообще.

С сериализацией все просто: метод виртуальный. Вызываем сериализацию для this. this будет указывать на потомка, и форматтер сам все сделает.

А как десериализоваться?


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
mihryak
Дата 3.8.2008, 01:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



ведь можно в базовом классе сделать что-то вроде моего кода - в базовом классе определить типы полей или свойств для сериализации, их вытаскивать через рефлексию
в десериализации главным тогда станет вопрос, как создать инстанс именно нужного типа (при использовании форматтера это проблема отпадает, но появляются некоторые другие smile)
при этом делать указанные методы виртуальными, наверное, не стоит, раз потомки не должны вмешиваться в процесс

и всё же - из чего и какими средствами планируется проводить (де)сериализацию?
PM MAIL ICQ   Вверх
jonie
Дата 3.8.2008, 01:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 22
Всего: 118



для (де)сериализации используетя soapformatter.
виртуальность нужна для того чтобы иметь возможность писать такой код:
Код

class Base : ISerializable
{
 public virtual void Serialize()
 {
   SoapFormatter bf = new SoapFormatter();
   using (FileStream ms = new FileStream("somepath"))
   {
     SoapFormatter sf = new SoapFormatter();
     bf.Serialize(ms, this); // (!) для потомков будет сериализовываться объект потомков, т.к. функция виртуальная
   }
 }

//тоже виртуальный
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            foreach (FieldInfo fieldInfo in GetType().GetFields(FieldBindingFlags))
            {
                info.AddValue(fieldInfo.Name, fieldInfo.GetValue(this));
            }
        }
}
.....
Base o = new Deriv();
o.Serialize(); //сериализуем _потомок_, методом родителя

хочу также для десериализации 8-)
но по умолчанию Soap форматтер бросает исключение, если не находит в Deriv десериализующего конструктора (что и понятно).

вот думаю, а не написать ли свой форматтер, который будет искать конструктор и в предках, и использовать его.....

Это сообщение отредактировал(а) jonie - 3.8.2008, 01:18


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
mihryak
Дата 3.8.2008, 01:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



да, десериализирующий конструктор нужен в наследниках..
но ведь и аттрубут [Serializable] тоже нужен. может, приемлимо будет принять соглашение об обязательном наличии в наследниках этого конструктора с пустым телом?
Код

            [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
            protected DerivedTest(SerializationInfo info, StreamingContext context) : base(info, context)
            {
            }


а виртуальность и правда не нужна, ведь this всегда будет правильного типа со своим собственным набором полей, так что всё будет работать
дополнил свой тестик новым классом (привожу весь код, т.к. потребовались небольшие изменения в базовом классе - см. ниже)
Код

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;

namespace SerializationTest
{
    class Program
    {
        [Serializable]
        public class Test : ISerializable
        {
            private const BindingFlags FieldBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;

            protected readonly int intValue;
            protected readonly string stringValue;

            public Test(int intValue, string stringValue)
            {
                this.intValue = intValue;
                this.stringValue = stringValue;
            }

            public int IntValue
            {
                get { return intValue; }
            }

            public string StringValue
            {
                get { return stringValue; }
            }

            public override string ToString()
            {
                return String.Format("IntValue = [{0}], StringValue = [{1}]", IntValue, StringValue);
            }

            #region ISerializable Members

            void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
            {
                foreach (FieldInfo fieldInfo in GetType().GetFields(FieldBindingFlags))
                {
                    info.AddValue(fieldInfo.Name, fieldInfo.GetValue(this));
                }
            }

            #endregion

            [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
            protected Test(SerializationInfo info, StreamingContext context)
            {
                foreach (SerializationEntry serializationEntry in info)
                {
                    GetType().GetField(serializationEntry.Name, FieldBindingFlags).SetValue(this, serializationEntry.Value);
                }
            }

        }

        [Serializable]
        public class DerivedTest : Test
        {
            private readonly double doubleValue;

            public DerivedTest(int intValue, string stringValue, double doubleValue)
                : base(intValue, stringValue)
            {
                this.doubleValue = doubleValue;
            }

            [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
            protected DerivedTest(SerializationInfo info, StreamingContext context) : base(info, context)
            {
            }

            public double DoubleValue
            {
                get { return doubleValue; }
            }

            public override string ToString()
            {
                return String.Format("IntValue = [{0}], StringValue = [{1}], DoubleValue = [{2}]", IntValue, StringValue, DoubleValue);
            }
        }

        static void Main()
        {
            Test test = new DerivedTest(5, "string", 2.2);
            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream stream = new MemoryStream())
            {
                formatter.Serialize(stream, test);
                stream.Position = 0;
                test = (Test) formatter.Deserialize(stream);
            }
            Console.WriteLine(test);
            Console.ReadKey();
        }
    }
}

получается, что никаких дополнительных действий по (де)сериализации отнаследованный класс не предпринимает, но он должен иметь атрибут Serializable и иметь пустой десериализующий конструктор
ещё одно ограничение - все поля, которые нужно сериализовать из базового класса, должны быть хотя бы protected, иначе GetFields(), вызванный у наследника, их попросту не вернёт

свой форматтер - это, конечно, хорошо, но если он нужен универсальный без ограничений, учесть все детали будет очень непросто, много подводных камней встретится

Это сообщение отредактировал(а) mihryak - 3.8.2008, 01:49
PM MAIL ICQ   Вверх
Idsa
Дата 3.8.2008, 08:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2086
Регистрация: 5.12.2006
Где: Томск

Репутация: 14
Всего: 62



 smile 
Тема топика - "сериализация самого себя" - напомнила мне фразу из одной книги по .NET:
Цитата

Teleportation in science fiction is a good example of serialization (though teleportation is not currently supported by the .NET Framework)



--------------------
Мой блог: alexidsa.blogspot.com
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0759 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.