Ниже приведен след, где я = 0,1,2,3,4,5,6,7 (сбой)
Когда i = 0
код вызывает метод Test0()
.Этот метод просто перебирает некоторые «локальные» переменные и выводит результат.«Test0 = 12» Примечание: переменная i
является «локальной» и не является той же переменной i
, используемой в главном for
счетчике цикла.
if (i == 0) {
Test0(); //Test0 = 12
Console.WriteLine("Test0 = " + i.ToString());
} else...
private static void Test0() {
int result = 0;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 2; j++) {
result += i;
}
}
Console.WriteLine("Test0 = " + result.ToString());
}
Как только код возвращается из Test0()
… Вывод…
Test0 = 12
Примечание: переменная «local» i
из Test0
вышла из области видимости, а переменная счетчика i
в цикле for
выведена…
Test0 = 12
Test0 = 0
Когда i = 1
Код продолжается ... возвращается к циклу for
с шагом i = 1
.Вводит код ...
if (i == 1) {
Test1(i);
Console.WriteLine("Test1 = " + i.ToString());
} else...
private static void Test1(int i) {
i = 3;
}
Когда i = 1
код вызывает метод Test1(i)
.Этот метод принимает переменную int
в качестве параметра.Когда код входит в метод Test1(int i)
... создается новая переменная LOCAL i
.Начальное значение i
равно 1, которое было передано. Код просто устанавливает переменную «local» i
в значение Three (3), а затем возвращает.
Как только код возвращается из Test1(i)
* i
переменная, созданная в методе, больше не находится в области видимости, и следующая строка кода выведет переменную i
, используемую в счетчике цикла for
, которая по-прежнему равна единице (1).Вывод…
Test0 = 12
Test0 = 0
Test1 = 1
Когда i = 2
Код продолжается ... возвращается к циклу for
с шагом i = 2
.Вводит код ...
if (i == 2 && i % 2 == 0) {
Test2(ref i); //i=2
Console.WriteLine("Test2 = " + i.ToString());
} else...
private static void Test2(ref int i) {
i = 2;
}
Примечание ниже.Здесь переменная передается как ref
(ссылка).В настоящее время переменная for
counter i
равна 2. Когда код входит в метод Test2(ref int i)
, он НЕ создает свою собственную «локальную» копию.Переменная счетчика i
, используемая в основной программе, «подвержена» этому методу, и она «может» ее изменить… как код обязательно делает со следующей строкой кода: i = 2;
К счастью, текущее значение i
IS уже 2. Изменение i
таким способом крайне не рекомендуется, и я бы посчитал, что в лучшем случае это может быть рискованно, в худшем случае - сбой.
Продолжение… i
по-прежнему 2 после возврата из Test2(ref i)
Вывод…
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Когда i = 3
Код продолжается… Возвращается обратно к циклу for
с шагом i = 3
.Вводит код…
if (i == 3) {
Test3(ref i);
} else...
private static void Test3(ref int i) {
i = Convert.ToInt32(i + "1") % 9;
}
Когда i = 3
код вызывает метод Test3(ref i)
.Здесь, похоже, этот метод пытается «изменить» переменную счетчика i
в основном цикле.Чтобы разбить его, когда мы знаем, i = 3
…
i = Convert.ToInt32(i + "1") % 9;
Становится
i = Convert.ToInt32(“31”) % 9;
Это вернет четыре (4), поскольку 31 мод 9 = 4. Это значение основнойfor
переменная счетчика циклов i
установлена в.Это означает, что код будет пропущен, когда i=4
, поскольку здесь устанавливается значение 4 ... когда код возвращается к циклу for
... он собирается установить i
в 5. Кроме того, НЕТ выводакогда i = 3
… чтобы подвести итог, поскольку не было нового вывода… Это то же самое, что и предыдущая итерация цикла.
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Когда i = 5
Код продолжается ... возвращается к циклу for
, помните, что предыдущий вызов Test3(ref i)
изменился i
до четырех (4), следовательно, конструкция if
увеличивает i
до i = 5
.Вводит код ...
if (i == 5) {
Test5(i);
Test5(i - 2);
} else...
private static void Test5(int i) {
Program.value -= i; //value = 0
Console.WriteLine("Test5 = " + Program.value.ToString());
}
Когда i = 5
код вызывает метод Test5(i)
дважды.Метод Test5(int i)
принимает один int
параметр i
, затем вычитает значение i
из глобальной переменной value
.На этом этапе мы «знаем» value=0
, поэтому value
устанавливается в -5.Затем выводит value
… Output…
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5(i);
и возвращается второй вызов с Test5(i - 2);
…
Для отслеживания, i = 5
AND value = -5
…поэтому вышеуказанный вызов с использованием i-2
может быть переписан как…
Test5(3);
Здесь внутри Test5, i
= 3, код вычитает 3 из value
value = -8
, затем выводит…
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Когда i = 6
Код продолжается ... снова возвращается к циклу for
, увеличивается i
до i = 6
.Вводитметод code…
if (i == 6) {
Test6(ref i);
Console.WriteLine("Added item to dictionary.");
} else...
private static void Test6(ref int i) {
myDictionary.Add(i, "six");
Console.WriteLine("Test6 = " + myDictionary[i]);
}
Test6(ref int i)
добавляет значение в глобальный словарь myDictionary
и выводит его из словаря.Выход….
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Как только код возвращается из Test6(ref int i)
, выводится строка…
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.
Когда i = 7
Кодпродолжается… возвращается к циклу for
, увеличивается с i
до i = 7
.Вводит код…
if (myDictionary[i] == "six") {
Console.WriteLine("Item 6 is in the dictionary.");
}
else {
Console.WriteLine("Entered else clause");
int zero = 0;
int result = i / zero;
Console.WriteLine("Result is " + result.ToString());
}
Приведенный ниже код вызывает исключение.
myDictionary[i] == "six"
Так как i = 7
, myDictionary[i]
собирается выйти из строя и выдает «ключ», которого нетв словарном исключении, и это имеет смысл, так как мы знаем, что в словаре есть только один элемент, и он равен 6. Поэтому исключение перехватывается, и дисплей обновляется…
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.
Catch clause entered
Предложение finally
оператора try выполняется….
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.
Catch clause entered
Finally clause entered
Наконец, выводится последняя строка и код завершается.Выходные данные…
Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.
Catch clause entered
Finally clause entered
Finished
Ниже составное условие if
(и последующее) не имеет большого смысла.Если i
НЕ равно двум (2), тогда (из-за короткого замыкания) вторая часть условия «и» никогда не будет оцениваться.Следовательно, i % 2 == 0
будет оцениваться только тогда, когда i=2
???Я уверен, что по модулю (2,2) всегда будет возвращаться 0. Суть в том, что второе условие никогда не оценивается, если только i = 2
, которое всегда будет истинным, поэтому этот if
можно переписать как if (i == 2)
.Вот почему «второй» оператор if (i == 2)
в части «else» этого оператора if (i == 2)
НИКОГДА не будет выполнен.
else if (i == 2 && i % 2 == 0) {
Test2(ref i); //i=2
Console.WriteLine("Test2 = " + i.ToString());
}
else if (i == 2)
{… never get here….
Чтобы помочь, я рекомендую вам взглянуть поближе на «красный флаг»В коде.Передача по ref не является большой проблемой, однако передача «индекса» цикла по ref и изменение его значения - это огромный красный флаг.Отслеживание кода стало более сложным.Это то, что вам нужно полностью понять, следовательно, тест.Тест выполняет что-то (изменение индекса цикла), что вы редко видели бы в любой среде.Поэтому при отслеживании кода, который делает это, требуется особая осторожность.