Почему следующие строки кода не создают предупреждение компилятора?
void Main()
{
throw new Exception();
throw new Exception();
}
Как я вижу, компилятор должен сообщить вам, что исключение второго броска не может быть достигнуто.
Почему следующие строки кода не создают предупреждение компилятора?
void Main()
{
throw new Exception();
throw new Exception();
}
Как я вижу, компилятор должен сообщить вам, что исключение второго броска не может быть достигнуто.
Это явно ошибка компилятора, и она была введена в С# 3.0 - практически в то время, когда я в значительной степени реорганизовал проверку доступности. Это, вероятно, мое плохое, извините.
Ошибка полностью доброкачественна; в основном, мы просто забыли случай в предупреждающем репортере. Мы правильно генерируем информацию о достижимости; как отмечали другие, мы правильно обрезаем недостижимый код перед codegen.
Ошибка - это не что иное, как недостающий случай в генераторе предупреждений. У нас есть какой-то хитрый код, который гарантирует, что мы не сообщим о миллионах предупреждений, когда вы делаете какой-то большой раздел кода недостижимым. У компилятора есть код для специфического сообщения предупреждений о безусловных gotos ( "goto", "break", "continue" ), условных gotos ( "if", "while" и т.д.), Try-catch-finally (который включает в себя эквивалентные формы (например, блокировка и использование), блоки, возврат (возврат доходности и регулярный возврат), локальные объявления, помеченные операторы, переключатели и выражения.
Вы видите в этом списке слова "throw"? И я нет. Это потому, что мы это забыли.
Извините за неудобства. Я отправлю записку в QA, и мы исправим это в будущей версии языка.
Спасибо, что привлек это к моему вниманию.
Он может дать предупреждение/ошибку компилятора, но, к сожалению, это не так. Но если вы посмотрите на код IL, рассматривается только первое исключение. Вы можете войти на сайт connect.microsoft.com и поднять его как что-то, что вы хотели бы видеть.
если вы ILDasm код ниже
static void Main(string[] args)
{
Console.Write("Line 1");
throw new Exception();
throw new Exception();
Console.Write("Line 4");
}
Вы получите это
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 18 (0x12)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Line 1"
IL_0006: call void [mscorlib]System.Console::Write(string)
IL_000b: nop
IL_000c: newobj instance void [mscorlib]System.Exception::.ctor()
IL_0011: throw
} // end of method Program::Main
После первого объекта Exception ничего не преобразуется в IL.
Эта ошибка (как называет ее Lippert) имеет некоторые странные последствия. Конечно, код, подобный этому, также не дает предупреждений о компиляции:
static int Main()
{
return 0;
throw new Exception("Can you reach me?");
}
Если вы креативны, вы все равно можете заставить оператор throw
вызывать (несвязанные) предупреждения. В этом любопытном примере код генерирует предупреждение только потому, что "зеленый" недоступен:
static int Main()
{
return 0;
throw new Exception(((Func<string>)(() => { if (2 == 2) { return "yellow"; } return "green"; }))());
}
(код просто создает экземпляр делегата из лямбда и вызывает делегата).
Но этот пример проще и выглядит хуже:
static int Main()
{
int neverAssigned;
return 0;
throw new Exception(neverAssigned.ToString());
}
Этот последний пример кода также компилируется без предупреждения! В "использовании" neverAssigned
нет проблем, потому что "использование" недоступно. Но вы также не получаете предупреждения о локальной переменной, которой никогда не присваивали (и никогда не "действительно" читали). Поэтому повторить, никакого предупреждения вообще, что кажется очень неправильным.
Интересно, изменится ли это поведение в будущих версиях Visual С#? Изменение этого даст людям предупреждения, которых у них не было раньше (что, на мой взгляд, они заслуживают).
Дополнение: Это поведение не меняется с помощью Roslyn, основанного на С# 6.0 компилятора Visual Studio 2015.