Рассмотрим следующий источник:
static void Main(string[] args)
{
bool test;
Action lambda = () => { test = true; };
lambda();
if (test)
Console.WriteLine("Ok.");
}
Он должен компилироваться, верно? Ну, это не так. Мой вопрос: в соответствии со стандартом С#, должен ли этот код компилироваться или это ошибка компилятора?
Сообщение об ошибке:
Use of unassigned local variable 'test'
Примечание: я знаю, как исправить ошибку и частично знаю, почему это происходит. Однако локальная переменная назначается безоговорочно, и я думаю, что компилятор должен это заметить, но он этого не делает. Интересно, почему.
Комментарий к ответам: C# позволяет объявлять неназначенные переменные, и это на самом деле весьма полезно, т.е.
bool cond1, cond2;
if (someConditions)
{
cond1 = someOtherConditions1;
cond2 = someOtherConditions2;
}
else
{
cond1 = someOtherConditions3;
cond2 = someOtherConditions4;
}
Компилятор правильно компилирует этот код, и я думаю, что оставление переменных неназначенными на самом деле делает код немного лучше, потому что:
- Он сообщает читателю, что значения присваиваются позже (вероятнее всего, в следующем условном выражении)
- Заставляет программиста присваивать переменные во всех ветках внутренних условий (если это было целью данного кода с самого начала), т.к. компилятор откажется компилировать код, если одна из веток не присвоит ни одной из них.
На полях: это еще интереснее. Рассмотрим тот же пример на C++:
int main(int argc, char * argv[])
{
bool test;
/* Comment or un-comment this block
auto lambda = [&]() { test = true; };
lambda();
*/
if (test)
printf("Ok.");
return 0;
}
Если вы закомментируете блок, компиляция завершится предупреждением:
main.cpp(12): warning C4700: uninitialized local variable 'test' used
Однако, если вы удалите комментарий, компилятор не выдаст никаких предупреждений. Мне кажется, что он способен определить, установлена ли переменная все-таки.
test
, достигнута. Я не знаю, связано ли это с базовым анализом потока кода, который не следует за вызовами методов, или это связано с тем, как закрытые над локальными переменными превращаются в члены класса, сгенерированные кодом, или, возможно, и то, и другое, или ни то, ни другое. Но в любом случае инициализируйте переменную значением false при объявлении. - person Anthony Pegram   schedule 09.01.2013test
присваивание достигнуто, когда на пути нет условных выражений? - person Spook   schedule 09.01.2013guess why
), но вместо этого решили написать свой собственный небольшой мистический роман о стеке. - person Earlz   schedule 09.01.2013delegate
? Вам не нужно использовать лямбду, не так ли? - person Chris Farmer   schedule 09.01.2013delegate { test = true; };
). Во-вторых, знать, что локальная переменная присваивается внутри делегата, несложно. На самом деле, чтобы поддерживать семантику замыкания, необходимо уже знать, что локальный объект доступен в замыкании, и поднять его. Сложный вопрос заключается в том, чтобы определить, выполняется ли этот делегат в какой-то момент, и пометить переменную как имеющую определенное значение в этот момент. В общем случае это нетривиальная задача. - person Servy   schedule 09.01.2013