How can I implement ISerializable in .NET 4 without violating inheritance security rules?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
If you really need ISerializable in .NET 4, the safe pattern is not just "implement GetObjectData and move on." You also need the correct serialization constructor, input validation during deserialization, and a clear inheritance story. In many cases, the simplest way to avoid inheritance-related security problems is to seal the class.
The Design Choice Comes First
Before writing code, decide whether the type should be inheritable.
- If the type does not need inheritance, make it
sealed. - If inheritance is required, use the standard protected serialization constructor and allow derived types to extend serialization explicitly.
Why this matters: custom serialization can expose object internals, and inheritance complicates who controls that data contract. A poorly designed base class can let derived classes deserialize the object into an invalid or unsafe state.
The Core ISerializable Pattern
A correct implementation has these pieces:
- the type is marked
[Serializable] - it implements
ISerializable - it defines a special deserialization constructor
GetObjectDatawrites all required state- the constructor validates what it reads back
Here is a small sealed example:
This pattern keeps the serialization contract local to one sealed type, which is the least risky option.
If the Class Must Be Inheritable
For an unsealed base class, the deserialization constructor should be protected, not private, so derived classes can participate correctly.
GetObjectData should also be virtual so a derived class can call the base implementation and then add its own values.
A derived type then extends the contract explicitly:
This is the important inheritance rule: base and derived types must cooperate instead of each trying to own the full serialized state independently.
Practical Security Guidance
If your real concern is security, the strongest advice is broader than syntax:
- validate everything during deserialization
- keep invariants enforced in the serialization constructor
- prefer sealed types unless extensibility is truly required
- avoid custom binary serialization entirely for new designs when a safer serializer fits the problem
In modern .NET guidance, custom binary serialization is considered legacy territory. But if you are maintaining a .NET 4 codebase, the pattern above is the one to follow.
Common Pitfalls
The most common mistake is forgetting the special serialization constructor. Without it, deserialization cannot reconstruct the object correctly.
Another mistake is making an inheritable type but keeping serialization logic non-virtual or private in the wrong places. That breaks derived classes and encourages unsafe workarounds.
A third pitfall is deserializing fields without validation. ISerializable gives you control, which means you are also responsible for rejecting invalid state.
Summary
- If possible, seal the class and keep the
ISerializablecontract local to that type. - Mark the type
[Serializable], implementGetObjectData, and provide the special serialization constructor. - For base classes, use a
protectedserialization constructor and avirtualGetObjectDatamethod. - Always validate deserialized values before accepting them as object state.
- Treat
ISerializableas legacy infrastructure and use it carefully in .NET 4 maintenance code.

