У меня слабое воображение, когда дело доходит до имен, поэтому я часто нахожу себя повторно использующим идентификаторы в своем коде. Это заставило меня столкнуться с этой конкретной проблемой.
Вот пример кода:
public delegate void TestDelegate(int test);
public class Test
{
private int test;
private void method(int aaa)
{
TestDelegate del = test => aaa++;
test++;
}
public static void Main()
{
}
}
Вот ошибки компиляции (вывод ideone):
prog.cs(11,3): error CS0135: `test' conflicts with a declaration in a child block
prog.cs(9,22): (Location of the symbol related to previous error)
Compilation failed: 1 error(s), 0 warnings
Строка 11 содержит test++
, строка 9 содержит лямбда.
Кстати, Visual Studio 2013 дает другую ошибку:
'test' conflicts with the declaration 'Namespace.Test.test'
Ошибка происходит только при инкрементах только в строке 11.
Код компилируется успешно, если я прокомментирую либо строку 9 (лямбда), либо строку 11 (приращение).
Эта проблема для меня неожиданна - я был уверен, что имена параметров лямбда могут конфликтовать только с именами переменных локального метода (что подтверждается компиляцией кода при компиляции инкремента). Кроме того, как параметр lambda может влиять на приращение, которое находится прямо за пределами лямбда?
Я не могу обдумать это... Что именно я сделал неправильно? И что означают сообщения об ошибках в этом случае?
ИЗМЕНИТЬ после всех отличных ответов:
Итак, я думаю, что, наконец, понял правило, которое я сломал. Это не хорошо сказано в спецификации С# (7.6.2.1, см. Ответ Джона Скита для цитаты). То, что должно было означать, это что-то вроде:
Вы не можете использовать один и тот же идентификатор для обозначения разных вещей (сущностей) в одном и том же "пространстве декларации локальной переменной", если одно из используемых нарушений (непосредственно) находится в области видимости, из области, где другая находится (непосредственно) расположена.
Не стандартная стандартная фраза, но я надеюсь, вы поняли, что я имею в виду. Это правило должно было разрешить это:
{
int a;
}
{
int a;
}
потому что ни одна из областей двух переменных a
не может быть "видима" из другой области;
и запретить это:
{
int a;
}
int a;
потому что второе объявление переменной "видно" из первой области видимости переменной
и запретить это:
class Test
{
int test;
void method()
{
{
int test;
}
test++;
}
}
потому что приращение поля можно "увидеть" из области блока (это не объявление не имеет значения).
Кажется, что С# 6 изменило это правило, в частности, чтобы закончить последний пример (и мой исходный код), хотя я действительно не понимаю, как именно.
Пожалуйста, исправьте меня, если я допустил некоторые ошибки в этих примерах.