When a class implements ISerializable, the serialization infrastructure calls GetObjectData during serialization. Inside this method, the object populates the SerializationInfo collection with name/value pairs representing the data that must be persisted. During deserialization, a special constructor that takes SerializationInfo and StreamingContext parameters is invoked. In this constructor the object retrieves the stored values from the SerializationInfo and restores its internal state.
Implementing ISerializable is often combined with the [Serializable] attribute. The attribute marks the type as eligible for serialization, while ISerializable customizes the actual data that is serialized. Without the attribute, the runtime will not serialize the type even if ISerializable is implemented.
Common use cases include handling complex object graphs, securing sensitive data by controlling what is exposed, preserving read‑only fields, or supporting version tolerance by adding extra fields and handling their absence during older deserialization.
Care must be taken to maintain compatibility across versions. Changing the names of serialized values or the order of fields can break deserialization of older binary files. A recommended practice is to use unique names and to provide robust fallback logic for missing entries.
Security concerns arise because deserialization can instantiate arbitrary types. Microsoft recommends avoiding BinaryFormatter with untrusted data and instead using safer serializers such as DataContractSerializer or System.Text.Json. When ISerializable is used, developers should validate the SerializationInfo contents and ensure that no malicious data can be injected.