Подтвердить что ты не робот

Почему бросание 2 исключений в строке не генерирует недопустимый код предупреждения?

Почему следующие строки кода не создают предупреждение компилятора?

void Main()
{
  throw new Exception();
  throw new Exception();
}

Как я вижу, компилятор должен сообщить вам, что исключение второго броска не может быть достигнуто.

4b9b3361

Ответ 1

Это явно ошибка компилятора, и она была введена в С# 3.0 - практически в то время, когда я в значительной степени реорганизовал проверку доступности. Это, вероятно, мое плохое, извините.

Ошибка полностью доброкачественна; в основном, мы просто забыли случай в предупреждающем репортере. Мы правильно генерируем информацию о достижимости; как отмечали другие, мы правильно обрезаем недостижимый код перед codegen.

Ошибка - это не что иное, как недостающий случай в генераторе предупреждений. У нас есть какой-то хитрый код, который гарантирует, что мы не сообщим о миллионах предупреждений, когда вы делаете какой-то большой раздел кода недостижимым. У компилятора есть код для специфического сообщения предупреждений о безусловных gotos ( "goto", "break", "continue" ), условных gotos ( "if", "while" и т.д.), Try-catch-finally (который включает в себя эквивалентные формы (например, блокировка и использование), блоки, возврат (возврат доходности и регулярный возврат), локальные объявления, помеченные операторы, переключатели и выражения.

Вы видите в этом списке слова "throw"? И я нет. Это потому, что мы это забыли.

Извините за неудобства. Я отправлю записку в QA, и мы исправим это в будущей версии языка.

Спасибо, что привлек это к моему вниманию.

Ответ 2

Он может дать предупреждение/ошибку компилятора, но, к сожалению, это не так. Но если вы посмотрите на код 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.

Ответ 3

Эта ошибка (как называет ее 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.