BinaryFormatter has very unusual powers, nothing else resembles what it does. It can create an object of your class without running its constructor. And it can give a value to your properties without running the property setter accessor methods.
Otherwise nothing particular magical about this, it simply persists the values of the fields of your class object. And restores them when the object is deserialized.
Not every class is suitable to be treated like this, either because of security concerns or because field values depend on runtime state too much. Note how security is an issue since an attacker could manipulate the serialized data and get your object into an inconsistent state, state that is exploitable. Say an IsAdministrator property. A good example of critical runtime state is the Control.Handle property, it can never have the same value when you deserialize.
These are practical constraints that the BinaryFormatter class can not figure out by itself. It needs help, an explicit okay that it is safe to do this. This cannot be a formal okay when you write the code to de/serialize the object, that would be easy but it in practice you don't know enough about the class since you did not write it. The class author needs to do this, they do so by giving it the [Serializable] attribute.
BinaryFormatter
explicitly check presence of this attribute and throw exception if it absent. – Radiophone