Странное сообщение об ошибке


6 0

Сегодня написал метод, который выглядел примерно так:

public methodName(int id) {
  int i = id + 1;
  ...
  ...
}

Компилирую и вижу вот такое сообщение об ошибке от компилятора: Source.cs:869 - Cannot use local variable 'id' before it is declared. Сижу, смотрю на ошибку и думаю, толи я идиот, то ли компилятор C# сегодня решил повыделываться. Вот же оно объявление переменной, которая передается в метод и тут же я его использую. С какого перепуга он мне говорит, что он не видит объявления?

Я минут пять не верил своим глазам, смотрел на ошибку и смотрел на код, но не могу понять, где же я лохонулся. Решил сделать вот такой вот финт:

public methodName(int id) {
  int id;
  int i = id + 1;
  ...
  ...
}

На этот раз получаю вполне логичную ошибку: A local variable named 'id' cannot be declared in this scope because it would give a different meaning to 'id', which is already used in a 'parent or current' scope to denote something else. И тут я вижу, что у меня такая ошибка не одна, а две в разнях строках.

Я показал только набросок метода, который я накатал, но на самом деле он был размером с 30 строк и ошибок было 5. Я же обратил внимание только на первую и вторую. Во второй была банальная опечатка The name 'notee' does not exist in the current context. Реальная ошибка была почти в конце метода:

public methodName(int id) {
  int i = id + 1;
  ...
  ...
  int id = InsertToDB();
  ...
}

Компилятор почему-то проругался на первую строку, хотя она вполне легальна. Некорректна строка со вторым объявлением переменной id. Но это объявление почему-то снесло крышу компилятору и он стал ругаться на первое объявление. В принципе, косяк действительно был в моем коде, просто впервые вижу, чтобы первая ошибка была следствием последней. В основном компилятор показывает все последовательно и логично и можно последовательно латать свои баги.


Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым


Комментарии

Sergey

09 Февраля 2012

По моему в Delphi всегда так: одна какая то ошибка, а компилятор показывает штук по несколько в разных местах. Исправляем одну и остальные пропадают сами.


Михаил Фленов

09 Февраля 2012

Это нормальная ситуация, когда первая ошибка является причиной для второй, третьей и даже 10-й ошибки. Код анализируется последовательно, и по умолчанию не останавливается на первой найденой ошибке. Такое я вижу часто. Но чтобы 4-я ошибка была причиной первой, вижу впервые. На мой взгляд, немного не логично.


09 Февраля 2012

Не поленился, набрал код. Все логично, компилятор выделяет 1-ю строку кода и пишет, что невозможно использовать локальную переменную до её объявления. Что не логичного??? Если ты объявляешь её ниже.


Михаил Фленов

10 Февраля 2012

Не логично, потому что у тебя есть параметр с таким именем и компилятор должен видеть эту переменную в параметре. Логичной является ошибка  A local variable named 'id' cannot be declared in this scope because it would give a different meaning to 'id', потому что именно она вызывает проблему.


Sat

10 Февраля 2012

Все дело в том, что современные компиляторы взяли за правило компилировать код не останавливаясь на возможных ошибках. То есть, сперва компилируем всё и выводим все найденные ошибки. Это возможно сделать только если за первый проход компилятора ошибки определялись синтаксическим анализатором компилятора и записывались в массив или список. Давайте просмотрим что при таком подходе происходит.
Итак строка:
methodName(int id)
допустим, что (утрировано) переменные и их типы мы храним в списке List[Name]=Type и в этой строке список преобретает такое значение List[id]=int, ну то есть в список мы записываем имя переменной и её тип.

Далее анализатор натыкается на данную строку
int id = InsertToDB();
Естественно если он не может определить тип какой то переменной, то, что бы продолжить компилирование он должен присвоить тип и значение по умолчанию данной переменной. В итоге имеем следующее:
List[InsertToDB]=Unknown
или другой тип отличный от int и, что бы не допустить ошибки при дальнейшей компиляции необходима замена
List[id]=int на List[id]=Unknown так как язык является строго типизированым и типы должны совпадать. Уж почему в этом случае тип по умолчанию берётся неопределённый остаётся спросить разработчиков?

И напоследок, при втором проходе сравниваются типы переменных и получается, что в строке
int i = id + 1;
id имеет тип Unknown о чем и сообщает компилятор.

Я вообще к таким выкрутасам мысли разработчиков отношусь не одобрительно, так как это вводит программиста в заблуждение, что может привести к трудностям восприятия своего же кода, как и произошло с вами Михаил.


Михаил Фленов

10 Февраля 2012

Прекрасно понимаю, почему это произошло. Просто локальная переменная объявленная внутри метода,имеет приоритет над переменными класса. Если у тебя есть что-то типа:


class MMM{
  int i = 10;

  voi Method() {
    int i = 20;
    // - здесь i будет использоваться локальная
  }
}


Это нормальная ситупция и это давно так принято. В данном случае у компилятора нет ошибки и он прав. Я просто описал то, что увидел, просто потому, что впервые увидел такое. Это не косяк, это не ошибка MS, это просто такое поведение. Компилятор действительно, когда анализирует код, видит строку:

int id = InsertToDB();

Он видит, что это первое объявление переменной id внутри данного метода, а это легально для него, потому что локальные имеют приоритет. На втором проходе происходит косяк, потому что на этом этапе он уже видит, что две переменные конфликтуют.

Хотя это легко исправить, просто локальная переменная не должна иметь приоритета над параметрами метода и тогда косяк можно было бы выловить уже на первом проходе. Но тут я не знаю точного алгоритма работы компилятора и не интересовался, возможно у MS были причины

Еще раз говорю, в данном случае никакого упрека в сторону компилятора и в сторону дороговизны XBox Live Gold. Я просто описал то, с чем столкнулся.


Добавить Комментарий

Еще что-нибудь

Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне