Потому что, если вы пропустите вызов деструктора (например, не используя RAII), ваши неуправляемые ресурсы будут просачиваться, и среда выполнения .NET не сможет ничего с ними поделать.
Если вы очистите свои неуправляемые ресурсы в финализаторе, то среда выполнения запустит это, даже если вы испортили свой код и позволили ссылке на ваш объект куда-то улететь:)
По сути, если ваш код содержит ошибки, вы не можете рассчитывать на вызываемый деструктор, но финализатор всегда будет вызываться, когда объект утилизируется сборщиком мусора.