В C # конструктор запускает последовательность:
Perform all field initializers
Chain to base class constructor
Execute user-supplied code for constructor
В vb.net последовательность:
Chain to base class constructor
Perform all field initializers
Execute user-supplied code for constructor
Нет основанной на Framework причины, почему C # делает вещи в том же порядке, о чем свидетельствует, что vb.net может и делает их в другой последовательности. Обоснование дизайна для подхода C # состоит в том, что не должно быть никакой возможности подвергнуть объект воздействию внешнего мира до того, как будут запущены все инициализаторы полей (для полей производного, а также полей базового класса); поскольку конструктор базового класса может предоставлять объект внешнему миру, выполнение этого требования означает, что инициализаторы полей должны выполняться перед конструктором базового класса.
Лично я не считаю это оправдание особенно убедительным. Существует много сценариев, в которых невозможно установить для полей полезные значения без информации, которая не будет доступна до запуска базового конструктора. Любой код, базовый конструктор которого может предоставлять частично построенные экземпляры, должен быть подготовлен для такой возможности. Хотя бывают моменты, когда было бы полезно указать, что инициализатор поля должен запускаться «рано», я думаю, что существует гораздо больше ситуаций, когда для них полезно иметь возможность получить доступ к объекту опущения (в некоторой степени, потому что я считаю, что Поля класса, значения которых следует рассматривать как инварианты в течение времени жизни экземпляра класса, должны, когда это целесообразно, устанавливаться декларативно через инициализаторы, а не обязательно в конструкторе)
Кстати, одна функция, которую я хотел бы видеть как в vb.net, так и в C #, - это средство объявления полей, инициализированных параметрами, и псевдополей. Если у класса есть поле с инициализацией параметров определенного имени и типа, каждый конструктор для этого класса, который не связан с другим классом того же класса, должен содержать параметры с соответствующими именами и типами. Значения этих полей будут установлены в конструкторе, прежде чем что-либо еще будет сделано, и будут доступны для других инициализаторов полей. Псевдополя будут вести себя синтаксически как поля, за исключением того, что они будут только пригодными для использования в инициализаторах полей и будут реализованы как локальные переменные внутри конструкторов. Такая особенность сделает многие типы структур более удобными. Например, если тип должен содержать один конкретный экземпляр массива в течение своего времени жизни, он может сказать:
readonly param int Length;
readonly ThingType[] myArray = new ThingType[Length];
может показаться более приятным, чем необходимость создания массива в конструкторе класса (что не может произойти до тех пор, пока не будет запущен базовый конструктор) или (для vb.net) необходимость передачи длины конструктору базового класса, который затем может использовать его для установки поля (которое затем будет занимать пространство в классе, даже если его значение - как Length
выше - может быть избыточным).