What you call “three types of constructors,” is having Test(){}, construct{} and class construct{}, right? Because there’s also static construct{} says the manual, even if I never used it; and there’s also Test.with_another_set_of_parameters(TestEnum my_parameter){}.
Anyway, () usually implies that you could pass a parameter there; it’s not the case for the “construct”-like steps, so having it would look weird. Also, using specific keywords allows to not have to deal with people wanting this to be normal methods; for example, you cannot make this step virtual, protected, etc. (what would that mean?)
I also don’t understand the “not needed” comments in your suggested code: by definition, the “construct” step is always executed (it’s what’s creates the GObject), as opposed to the constructors that are more usual methods (can take parameters…) and are not necessarily called (you can have many constructors, and you only call one; or none). So, how are these two calls “not needed,” why the others are?
Edit: And I don’t remember what C# does, if you care to remember me that…
C# has named instance constructors, named static constructors and private named instance deconstructors.
No unnamed constructors or deconstructors.
However C# also requires a accessible constructor for inheritance.
I’m not sure what a construct keyword does other then let you inherit from a class without exposing the constructor.
I’m not a language designer, but (IIUC) the class construct and construct keywords are here because GObject has “type registration” and “instance registration” steps, that Vala exposes because it’s something that is always run at (first/every) object creation, even when called from the GObject creation methods (g_object_new() and friends). These keywords are not available for non-GObject classes, IIRC.
Why GObject works this way would probably need an explanation by someone more qualified than myself.