to the top
close form
Для получения триального ключа
заполните форму ниже
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS-Studio для специалистов Microsoft MVP
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
V3104. The 'GetObjectData' implementati…
menu mobile close menu
Проверка проектов
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Диагностика микро-оптимизаций (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Реализовано по запросам пользователей (C++)
Cтандарт MISRA
Стандарт AUTOSAR
Стандарт OWASP (C#)
Проблемы при работе анализатора кода
Дополнительная информация
toggle menu Оглавление

V3104. The 'GetObjectData' implementation in unsealed type is not virtual, incorrect serialization of derived type is possible.

20 Май 2016

Анализатор обнаружил незапечатанный класс, реализующий интерфейс 'ISerializable', но не реализующий виртуальный метод 'GetObjectData'. Это может привести к ошибкам сериализации в производных классах.

Рассмотрим пример. Пусть у нас имеются объявления базового и производного классов следующего вида:

[Serializable]
class Base : ISerializable
{
  ....
  public void GetObjectData(SerializationInfo info, 
                            StreamingContext context)
  {
    ....
  }
}

[Serializable]
sealed class Derived : Base
{
  ....
  public new void GetObjectData(SerializationInfo info, 
                                StreamingContext context)
  {
    ....
  }
}

Где-то есть код, выполняющий сериализацию объекта:

void Foo(BinaryFormatter bf, MemoryStream ms)
{
  Base obj = new Derived();
  bf.Serialize(ms, obj);
  ms.Position = 0;
  Derived derObj = (Derived)bf.Deserialize(ms);
}

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

Для решения проблемы необходимо определить метод 'GetObjectData' в базовом классе с модификатором 'virtual', а в производном – 'override'. Тогда корректный код может выглядеть так:

[Serializable]
class Base : ISerializable
{
  ....
  public virtual void GetObjectData(SerializationInfo info,
                                    StreamingContext context)
  {
    ....
  }
}

[Serializable]
sealed class Derived : Base
{
  ....
  public override void GetObjectData(SerializationInfo info, 
                                     StreamingContext context)
  {
    ....
  }
}

Если в базовом классе определена только явная реализация интерфейса, стоит также добавить неявную реализацию виртуального метода 'GetObjectData'. Рассмотрим пример. Предположим, что у нас имеются определения классов следующего вида

[Serializable]
class Base : ISerializable
{
  ....
  void ISerializable.GetObjectData(SerializationInfo info, 
                                   StreamingContext context)
  {
    ....
  }
}

[Serializable]
sealed class Derived : Base, ISerializable
{
  ....
  public void GetObjectData(SerializationInfo info, 
                            StreamingContext context)
  {
    ....
  }
}

В таком случае из производного класса будет невозможно обратиться к методу 'GetObjectData' базового класса, а значит, часть членов не будет сериализована. Для исправления ошибки помимо явной реализации в базовый класс необходимо добавить неявную реализацию виртуального метода 'GetObjectData'. Тогда исправленный код может выглядеть так:

[Serializable]
class Base : ISerializable
{
  ....
  void ISerializable.GetObjectData(SerializationInfo info, 
                                    StreamingContext context)
  {
    GetObjectData(info, context);
  }

  public virtual void GetObjectData(SerializationInfo info, 
                                    StreamingContext context)
  {
    ....
  }
}

[Serializable]
sealed class Derived : Base
{
  ....
  public override void GetObjectData(SerializationInfo info, 
                                     StreamingContext context)
  {
    ....
    base.GetObjectData(info, context);
  }
}

Если же подразумевается, что у класса не должно быть наследников, следует добавить модификатор 'sealed' к объявлению класса, что сделает его запечатанным.

Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо