Являются ли все исключения .NET сериализуемыми?

Можно ли сериализовать все объекты исключений .NET?

Ответ 1

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

Но при рассмотрении сериализуемости вам нужно рассмотреть как непосредственный класс, так и все типы, которые являются членами этого типа (это рекурсивный процесс). Базовый класс Exception имеет свойство Data, которое имеет тип IDictionary. Это проблематично, поскольку позволяет вам или кому-либо еще добавлять любой объект в исключение. Если этот объект не сериализуется, то сериализация Exception завершится с ошибкой.

По умолчанию реализация свойства Data выполняет некоторую базовую проверку, чтобы обеспечить добавление объекта сериализуемым. Но это несколько ошибочно.

  • Выполняет только проверку верхнего уровня для сериализуемости типа, и эта проверка выполняется только путем проверки Type.IsSerializable(а не проверки на 100%).  
  • Свойство является виртуальным. Выведенный тип исключения может переопределять и использовать Hashtable, которая делает проверку 0.

Ответ 2

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

Другими словами, все исключения ДОЛЖНЫ быть сериализуемыми, но некоторые пользовательские исключения из стороннего кода могут быть не в зависимости от того, как они реализованы.

Например, в эпоху .NET 1.0 исключения из официального поставщика базы данных Microsoft Oracle не были сериализованы из-за ошибок в их коде.

Ответ 3

Этот вопрос уже получил достаточный ответ, но для программистов, которые являются новичками в С# или Serialization, я думаю, что на самом деле очень полезно указать, что в общем случае исключения являются НЕ сериализуемыми!

Это может показаться немного провокационным, но позвольте мне объяснить.

Верно, что все Исключения реализуют интерфейс ISerializable, но это только предполагает, что он должен быть сериализуемым. Но реализация интерфейса НЕ делает объект Serializable (который в этом контексте подразумевает, что Исключение может быть как сериализованным, так и десериализованным).

Наиболее точный ответ на этот вопрос, как указывали другие, заключается в том, что многие, но, конечно, не все исключения в .Net Framework являются Serializable. Но если вопрос использует термин ".Net Exception" в более широкой области, например. Исключение, полученное из System.Exception, то лучший и более полезный ответ с точки зрения лучших практик и избежания ошибок - это утверждение, которое я сделал выше, что в целом Исключения не являются Serializable.

Вот почему: Как указывалось ранее, для того, чтобы Исключение было действительно Serializable, оно должно иметь соответствующий конструктор ctor(SerializationInfo, StreamingContext) и его необходимо украсить соответствующим атрибутом. Важно отметить, что ни одно из этих ограничений не вызывает ошибки компилятора, если они опущены!

Это означает, что класс НЕТ, полученный из Exception, является Serializable, если не выполняются эти дополнительные, необязательные (с точки зрения компилятора).

т.е. любой несезонный/не подозревающий кодер, который получает новое исключение, как показано ниже, только что создал исключение, которое НЕ является Serializable.

class MyNewException : Exception { }

В Visual Studio есть отличный фрагмент "Исключение", который позволяет быстро генерировать новые сериализуемые исключения. Но даже в этом случае нет ничего, чтобы напомнить или помочь программисту фактически сериализовать свойства объекта. Например, даже если класс ниже имел соответствующий конструктор и атрибут, свойство MyNewField не было бы сериализовано без дополнительного кода как в конструкторе, так и в GetObjectData.

class MyNewException : Exception 
{
    public MyNewField { get; set; }
}

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

В моих собственных проектах я в некоторых случаях создал исключение "Прокси", которое может хранить некоторую информацию (например, сообщение и т.д.) из Исключений, которые не сериализуются сами. Они могут использоваться для сериализации некоторой информации или, альтернативно, для десериализации данных, написанных Исключением, у которого нет соответствующего конструктора.

Ответ 4

System.Exception реализует ISerializable, но потомки могут не десериализоваться, если они не реализуют правильный перегруженный конструктор с сигнатурой (SerializationInfo,StreamingContext).