Не найден конструктор для десериализации объекта типа

Обновлено: 23.04.2024

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

Позволяет объекту управлять его собственной сериализацией и десериализацией.

Примеры

В следующем примере кода демонстрируется использование интерфейса для определения поведения пользовательской ISerializable сериализации для класса.

Комментарии

Любой класс, который может быть сериализован, должен иметь метку SerializableAttribute. Если классу необходимо управлять процессом сериализации, он может реализовать ISerializable интерфейс. Вызывается Formatter GetObjectData во время сериализации и заполняется предоставленными SerializationInfo всеми данными, необходимыми для представления объекта. Создает Formatter объект SerializationInfo с типом объекта в графе. Объекты, которые должны отправлять прокси-серверы для себя, могут использовать FullTypeName методы SerializationInfo для AssemblyName изменения передаваемой информации.

В случае наследования классов можно сериализовать класс, производный от базового класса, реализующего ISerializable. В этом случае производный класс должен вызывать реализацию GetObjectData базового класса внутри его реализации GetObjectData. В противном случае данные из базового класса не будут сериализованы.

Интерфейс ISerializable подразумевает конструктор с сигнатурой constructor (SerializationInfo information, StreamingContext context) . Во время десериализации текущий конструктор вызывается только после десериализации данных в SerializationInfo методе форматирования. Как правило, этот конструктор должен быть protected , если класс не sealed является .

Порядок десериализации объектов не гарантируется. Например, если один тип ссылается на тип, который еще не десериализован, возникнет исключение. При создании типов с такими зависимостями можно обойти проблему, реализовав IDeserializationCallback интерфейс и OnDeserialization метод.

Архитектура сериализации обрабатывает типы объектов, расширяющие MarshalByRefObject Objectтипы. Эти типы можно пометить с помощью SerializableAttribute интерфейса и реализовать ISerializable как любой другой тип объекта. Их состояние объекта будет записано и сохранено в потоке.

Как общий конструктивный шаблон, классу было бы необычно пометить как сериализуемый атрибут, так и расширение MarshalByRefObject. Разработчики должны тщательно думать о возможных сценариях сериализации и удаленного взаимодействия при объединении этих двух характеристик. Один из примеров, где это может быть применимо, — с .MemoryStream В то время как базовый класс MemoryStream (Stream) расширяется, MarshalByRefObjectможно записать состояние MemoryStream и восстановить его при необходимости. Таким образом, он может иметь смысл сериализовать состояние этого потока в базу данных и восстановить его в какой-то момент времени. Однако при использовании при удаленном взаимодействии объект этого типа будет прокси-сервером.

Дополнительные сведения о сериализации классов, расширяющих классы MarshalByRefObject, см. в разделе RemotingSurrogateSelector. Дополнительные сведения о реализации ISerializableсм. в разделе "Пользовательская сериализация".

Примечания для тех, кто реализует этот метод

Реализуйте этот интерфейс, чтобы разрешить объекту участвовать в собственной сериализации и десериализации.

Методы

Заполняет объект SerializationInfo данными, необходимыми для сериализации целевого объекта.

I am attempting to serialize/deserialize an object that contains a Dictionary . These are both custom types.

In my code I have a type of Template which contains the Dictionary . It is the Template class that I am attempting to serialize/deserialze.

To resolve the problem that this collection is a Dictionary I have implemented the ISerializable interface on my Template class.

The strategy here is to "unpack" the dictionary into two seperate lists and store them individually in the serialized stream. Then they are re-created afterwards.

My Section class also implments ISerializable .

The problem is that when I serialize GetObjectData() is called on both my Template and my Section which makes me believe that the data is Serializable and that its getting serialized.

When I deserialize, only the deserialize constructor on Template is called. The deserialize constructor for Section is never called. The result of this is that the call to info.GetValue("Section_Values". ) does return a List but it has one item in it and that item is null.

Why does my constructor to deserialize a Section never get called? Could it be that some of the data inside the section is not serializable? If so, how to find out what exactly it cannot serialize?

Update: One thing I have just spotted is that the BaseObject for section is marked with [Serializable] but does not implement ISerializable .

Additionally, Im wondering how fussy the Deserialize code is - will it target a constructor that also constructs a base class?

Update..

Ok, Ive tracked down the problem to the Serialization of the Section. The code looks something like this.

With both of the lines commented out, nothing is serialized and the deserialization constructor is called on Section . If I add in the string value everything is still fine. However, yes - you guessed it - if I add the CustomObject into the serialization stream then the deserialization constructor is not called.

  • My deserialization constructor for Section is a blank method - I dont attempt to do anything with the deserialized data.
  • The base constructor for Section has been stubbed out to pass in new valid objects and I have confirmed that this runs fine.
  • No exceptions are thrown to tell me that the CustomObject cannot be serialized.
  • The CustomObject is serializable and its GetObjectData() method runs fine and its constructed fine on deserialization.

It seems strange that purely be adding this serializable object to the stream that the framework then just fails to the deserializer constructor of Section !!

Есть объект, для которого сериализация и десериализация не осуществляется автоматически (в моём случае этот объект типа Matrix из Emgu CV). Как его сериализовать и десериализовать?

Я сделал обёртку MatrixDoubleWrap над эти объектом, хотелось бы, чтобы она проходила хотя бы вот такой тест:

MatrixDoubleWrap выглядит вот так (из интересного там только конвертация в массив массивов. Можно сериализовать этот массив массивов, но как сделать, чтобы автоматически сериализовывался и десериализовывался именно он?):

Подскажите пожалуйста, что нужно дописать для того, чтобы это заработало?

3 ответа 3

Для начала, вам надо сделать конструктор по умолчанию, чтобы при десериализации объект смог создаться.

Потом, вам надо расставить атрибуты [ScriptIgnore] на тех свойствах, которые вам надо выключить из сериализации. Я так понимаю, что это все кроме DataArray .

Но я предлагаю пойти другим путем - написать конвертер для Matrix :

Зарегистрировать конвертер типов можно через RegisterConverters или (для веб-сервисов) через конфиг.

Для класса JavaScriptSerializer можно определить свои конвертеры типов. Набросал небольшой пример, здесь есть класс Matrix, для которого определяется кастомный конвертер. Несмотря на отсутствие конструктора по умолчанию, десериализация происходит корректно. Надеюсь, пример натолкнет вас на решение.

@PavelMayorov если состояние объекта определяется только данными, которые можно вытащить через публичный интерфейс - то да, без вопросов. Но если там есть какие-нибудь хитрые дополнительные private-поля, то рефлексия понадобится.

Пусть класс Matrix несериализуем по каким-то причинам. Например, это такой класс:

Для начала, напишем конвертер для «ручной» сериализации. Чтобы не возиться с JSON-атрибутами вручную, положим нужные данные в JToken :

Имея такой конвертер, достаточно его применить.

Если класс Matrix доступен вам, «оснастите» его атрибутом JsonConverter :

Если класс Matrix лежит в другой библиотеке, и вы не можете добавить атрибут, но он лежит в вашем контейнере, тогда добавьте атрибут к нужному полю контейнера:

Теперь вы можете сериализировать и десериализировать ваш контейнер:

Если вы не можете и расставить атрибуты в контейнере (например, их слишком много), добавьте ваш конвертер в список конвертеров при сериализации:

поэтому, если вы десериализовали свой объект, его конструкторы не вызываются, но будет вызван конструктор по умолчанию его родителя. И не забывайте: все ваши сериализуемые объекты должны иметь стандартный конструктор без параметров.

во время десериализации доступный конструктор по умолчанию называется для первого класса в иерархии наследования, который не реализует Serializable.

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

когда есть родительское/дочернее отношение, это зависит от того, является ли родитель Сериализуемым или нет. Если родитель не serializable, супер конструктор будет работать! Если и родитель, и ребенок сериализуемы, то никакие конструкторы не вызываются.

  1. когда есть один класс, реализующий интерфейс Serializable?

  2. когда есть родительское/дочернее отношение и только дочерние реализации сериализуемы?

  3. когда есть родительское/дочернее отношение, и оба родителя и ребенка реализуют сериализуемый?

на мой взгляд ответ ваш вопрос :

1)Если один класс реализует сериализуемый и только этот класс не существует родительского класса. конструктор flow похож на конструктор по умолчанию будет вызов родительского класса, который не реализован сериализуемым. в этом случае это класс Object. таким образом, конструктор No-arg класса Object будет запущен и создаст фиктивный объект, а при вызове readObject() поле будет задано отражением и данными, которые сохраняются в памяти или файле.

2) если только дочерние реализации сериализуемы, тогда поток будет идти до базового класса, который не сериализуем. если базовый класс dierect не сериализован, то (этот класс должен иметь конструктор NO-Arg) конструктор NO-Arg будет выполняться для базового класса в этом случае.

3) Если все родители сериализованы, то поток перейдет в класс Object и конструктор No-Arg будет запущен класса Object.

Примечание: но вы можете сериализовать, реализовав externalizable интерфейс, а затем конструктор по умолчанию (NO-ARG) будет вызываться из этого класса только не родительского класса в процессе десериализации.

прежде всего во время десериализации не вызывается ни один construtor, значение всего поля будет задано отражением.

Если вы отмечаете свой класс Как сериализуемый, чем JVM, установите значение поля путем отражения во время десериализации, и после этого JVM ищет его супер-класс, и если это не отмечено как Сериализуемое, то конструктор по умолчанию вызовет, а затем вызовет следующий супер-класс и так далее.

посмотрите на этот сценарий:

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

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

Исключение, которое выдается при возникновении ошибки во время сериализации или десериализации.

Примеры

Комментарии

SerializationException HRESULT использует COR_E_SERIALIZATION со значением 0x8013150C.

SerializationException использует реализацию по умолчанию Equals , которая поддерживает равенство ссылок.

Список начальных значений свойств для экземпляра SerializationException, см. в разделе SerializationException конструкторы.

Конструкторы

Инициализирует новый экземпляр класса SerializationException стандартными свойствами.

Инициализирует новый экземпляр класса SerializationException из сериализованных данных.

Свойства

Возвращает коллекцию пар «ключ-значение», предоставляющую дополнительные сведения об исключении.

Получает или задает ссылку на файл справки, связанный с этим исключением.

Возвращает или задает HRESULT — кодированное числовое значение, присвоенное определенному исключению.

Возвращает экземпляр класса Exception, который вызвал текущее исключение.

Возвращает или задает имя приложения или объекта, вызывавшего ошибку.

Получает строковое представление непосредственных кадров в стеке вызова.

Возвращает метод, создавший текущее исключение.

Методы

Определяет, равен ли указанный объект текущему объекту.

При переопределении в производном классе возвращает исключение Exception, которое является первопричиной одного или нескольких последующих исключений.

Служит хэш-функцией по умолчанию.

При переопределении в производном классе задает объект SerializationInfo со сведениями об исключении.

Возвращает тип среды выполнения текущего экземпляра.

Создает неполную копию текущего объекта Object.

Создает и возвращает строковое представление текущего исключения.

События

Возникает, когда исключение сериализовано для создания объекта состояния исключения, содержащего сериализованные данные об исключении.

Читайте также: