Почему компилятор считает, что Environment.Exit может вернуться?

Пример кода:

switch(something)
{
    case 0:
        System.Environment.Exit(0);
    case 1:
        // blah ...
        break;
}

Он не будет компилироваться, потому что компилятор считает, что выполнение может вернуться из Exit(). Компилятор явно ошибается.

Никаких трюков. System.Environment.Exit() настоящий.

Мало того, что возвращение System.Environment.Exit() совершенно нелогично, я проследил код, и в итоге он вызывает ExitProcess(exitCode);, который не может вернуться.


person Joshua    schedule 01.09.2017    source источник
comment
Поскольку компилятор не может посмотреть на IL метода, чтобы узнать, что будет выполняться во время выполнения (поскольку у компилятора абсолютно нет возможности узнать, какая именно сборка будет загружена во время выполнения), как вы предложить компилятору знать, что данный метод никогда не возвращает значение?   -  person Alexei Levenkov    schedule 01.09.2017
comment
@AlexeiLevenkov: Учитывая текущую ситуацию, [System.Runtime.InteropServices.NoReturn] void Exit(int ExitCode); Если бы я писал это заново, то был бы тип (похожий на System.Void), означающий недостижимость.   -  person Joshua    schedule 01.09.2017
comment
Атрибуты не являются частью сигнатуры метода, поэтому он не будет работать, поскольку компилятор не может гарантировать, что во время выполнения библиотека, загруженная для реализации этого метода, даже будет иметь атрибут (игнорируя тот факт, что компилятору и JIT придется обеспечивать поведение этот атрибут каким-то образом). Действительно, возврат специального типа, который является частью сигнатуры метода, будет работать, но стоит ли создавать целую дополнительную инфраструктуру, которая проверяет, что метод не может вернуться для этого единственного особого случая метода, который завершает процесс?   -  person Alexei Levenkov    schedule 01.09.2017
comment
@AlexeiLevenkov: функция (out x) опровергает это. на самом деле [System.Runtime.InteropServices.Out]. Это не совсем специальное назначение; любой метод, гарантированно вызывающий исключение, может быть помечен этим тегом; также обратите внимание, что он есть в C и C++. Если вызвать библиотеку времени выполнения, в которой ее нет, код даже не загрузится, так что это небольшая проблема.   -  person Joshua    schedule 01.09.2017
comment
Компилятор просто подчиняется спецификации: конец точка expression_statement достижима, если это expression_statement достижимо.   -  person user4003407    schedule 02.09.2017


Ответы (1)


Что касается языка, то он может вернуться. Да, в реальной жизни процесс завершится до того, как у него будет возможность вернуться, но компилятор не знает об этом на основе сигнатуры метода.

Вам нужно будет добавить «перерыв», чтобы сделать компилятор счастливым.

person Tim    schedule 01.09.2017
comment
Трудно объяснить, что именно не так с этим ответом. Это похоже на то, что он отвечает что, а не почему. - person Joshua; 01.09.2017
comment
Представьте, что у вас есть метод под названием «Foo», который вызывает System.Environment.Exit(). Ожидаете ли вы, что оператор switch принудит к тому, что вы вызвали break после вызова Foo(), или вы ожидаете, что оператор switch поймет значение Foo, проверив пути своего кода, чтобы узнать, что он завершит процесс и никогда не сможет вернуться? - person Tim; 01.09.2017
comment
компиляторы не должны зависеть от побочных эффектов вызовов библиотек. Не гарантируется, что этот конкретный вызов сработает, он может вызвать исключение. - person Keith Nicholas; 01.09.2017
comment
Было время, когда я ожидал, что компилятор разберется в этом случае, но с тех пор я узнал, что это неоптимальный выбор, и он должен быть частью объявления. - person Joshua; 01.09.2017
comment
@KeithNicholas: если он выдает исключение, он все равно не проходит проверку. - person Joshua; 01.09.2017