ECMA-335 не обязывает CLI предоставлять гарантию того, что изменения инициализации, сделанные в конструкторе, должны быть видны до завершения конструктора:
Это явно не требование, чтобысоответствующая реализация CLI гарантирует, что все обновления состояния, выполняемые в конструкторе, будут равномерно видны до его завершения (см. там , раздел I.12.6.8 ).
Итак, краткий ответ: избегайте подписки обработчиков событий экземпляра внутри конструктора, поскольку это подразумевает передачу экземпляра внешним потребителям без гарантии того, что экземпляр готов к использованию.
Подробно: обычно семантика конструктора подразумевает только инициализацию состояния, которая переводит внутренние данные экземпляра в согласованное состояние (когда все его инварианты истинны и готовы к использованию другими объектами).Механизм событий в C # по сути является адаптацией паттерна наблюдателя, который подразумевает количество взаимодействий между его участниками, и создание подписки является одним из этих взаимодействий, и, как и любое другое взаимодействие с другим объектом, его следует избегать в конструкторе, когда экземпляр не существует.t гарантированно будет инициализирован.Вы правильно заметили возможный сценарий, когда он может стать проблемой, но даже с применением механизмов защиты, таких как переупорядочение или синхронизация, он не может быть гарантирован на 100% безопасным, поскольку он может быть не предоставлен реализацией CLI или даже если есть возможностьсценариев, когда конструктор не завершается по причине, не зависящей от кода внутри конструктора, например, из-за ThreadAbortException
.
Конечно, могут быть некоторые смягченные требования к дизайну, продиктованные некоторыми известными ограничениями(например, вы можете быть на 100% уверены, что ваш издатель событий реализован способом, исключающим критические сценарии), но в общем случае я бы предложил разделить сценарии построения и подписки, когда есть отдельный метод, который является частью общедоступногодоговор, который предназначен только для подписки.