Чому цикл for поводиться по-різному при міграції коду VB.NET на C #?


87

Я переходжу до проекту з Visual Basic на C #, і мені довелося змінити спосіб оголошення forциклу.

У VB.NET forцикл оголошено нижче:

Dim stringValue As String = "42"

For i As Integer = 1 To 10 - stringValue.Length
   stringValue = stringValue & " " & CStr(i)
   Console.WriteLine(stringValue)
Next

Які результати:

42 1
42 1 2
42 1 2 3
42 1 2 3 4
42 1 2 3 4 5
42 1 2 3 4 5 6
42 1 2 3 4 5 6 7
42 1 2 3 4 5 6 7 8

У C # forцикл оголошено нижче:

string stringValue = "42";

for (int i = 1; i <= 10 - stringValue.Length; i ++)
{
   stringValue = stringValue + " " + i.ToString();
   Console.WriteLine(stringValue);
}

І вихід:

42 1
42 1 2
42 1 2 3

Це, очевидно, неправильно, тому мені довелося дещо незначно змінювати код і включати цілочисельну змінну, яка містила б довжину рядка.

Будь ласка, дивіться код нижче:

string stringValue = "42";
int stringValueLength = stringValue.Length;

for (int i = 1; i <= 10 - stringValueLength; i ++)
{
   stringValue = stringValue + " " + i.ToString();
   Console.WriteLine(stringValue);
}

І вихід:

42 1
42 1 2
42 1 2 3
42 1 2 3 4
42 1 2 3 4 5
42 1 2 3 4 5 6
42 1 2 3 4 5 6 7
42 1 2 3 4 5 6 7 8

Тепер моє питання вирішує, як Visual Basic відрізняється від C # з точки зору Visual Basic, використовуючи stringValue.Lengthумову в forциклі, хоча кожен раз, коли цикл виникає, довжина рядка змінюється. Тоді як у C #, якщо я використовую умову stringValue.Lengthin forloop, це змінює початкове значення рядка кожного разу, коли виникає цикл. Чому це?


7
Microsoft чітко окреслює, в чому полягає ваша проблема ...
đöđěxěŕ

39
@ Çöđěxěŕ: Зупиніть, будь ласка. Якби роботовидалення тегів із заголовка без урахування контексту було корисним, веб-сайт зробив би це.
Ry-

11
@ Çöđěxěŕ Ви можете знайти деяку інформацію про це тут
pushkin

35
@ Çöđěxěŕ Я не думаю, що ці дописи суперечать один одному. Справа в тому, щоб не незграбно вклеювати тег у заголовок типу "запитання про цю річ - тег". Але якщо заголовок - це повне речення, що включає тег, то іноді це нормально. "Чому цикл for поводиться по-різному при міграції" здається занадто загальним заголовком.
pushkin

26
@ Çöđěxěŕ "перенесення коду VB.NET на C #" - це явно повна фраза, яка додає корисну інформацію до заголовка. Не вносіть зміни, що зменшують чіткість. Будемо сподіватися, що це поняття є достатньо здоровим глуздом, що нам не потрібна мета-публікація для його резервного копіювання.
jpmc26,

Відповіді:


115

У C # гранична умова циклу обчислюється на кожній ітерації. У VB.NET це обчислюється лише при вході в цикл.

Отже, у версії C # у питанні, оскільки довжина stringValueциклу змінюється у циклі, значення змінної остаточного циклу буде змінено.

У VB.NET остаточна умова є включною, тому ви б використовували <=замість <C #.

Оцінка кінцевого стану в C # має наслідком того, що навіть якщо воно не змінюється, але обчислити його дорого, його слід обчислити лише один раз перед циклом.


Дякую за відповідь. Тепер я усвідомлюю, що використання <=дозволяє мені робити ітерацію та отримувати такий самий результат, як і код VB. Однак мені більше цікаво дізнатися, чому мені довелося оголосити цілочисельну змінну, а VBмені не потрібно. Я збираюся оновити своє запитання, щоб показати той самий результат.
Sle423,

@ Sle423 Причина вказана в першому реченні моєї відповіді. Оскільки в stringValueциклі змінюється довжина , буде змінено значення змінної остаточного циклу.
Ендрю Мортон,

1
вибачаюся, дякую за цю відповідь. І дякую, що детальніше це для мене розробили.
Sle423

1
@ Sle423 Я додав це у відповідь, оскільки воно насправді це уточнює.
Ендрю Мортон,

22

Тепер моє запитання вирішує, як VB відрізняється від C # з точки зору VB, використовуючи умову stringValue.Length у циклі for, хоча кожен раз, коли відбувається цикл, довжина рядка змінюється.

Відповідно до документації VB.NET :

Якщо ви зміните значення counterперебування всередині циклу, ваш код може бути складнішим для читання та налагодження. Зміна значення start, endабо stepне впливає на значення ітерації , які були визначені , коли цикл був вперше введений.

Отже, значення To 10 - stringValue.Lengthобчислюється один раз і використовується повторно до виходу з циклу.

Однак подивіться на твердження c #

Якщо значення for_conditionнемає або якщо оцінка дає результат true, контроль передається у вбудований оператор. Коли і якщо контроль досягає кінцевої точки вбудованого оператора (можливо, після виконання оператора continue), вирази for_iterator, якщо такі є, обчислюються послідовно, а потім виконується інша ітерація, починаючи з оцінки for_conditionв кроці вище.

Що в основному означає, що стан ; i <= 10 - stringValueLength; оцінюється щоразу знову.

Отже, як ви бачили, якщо ви хочете відтворити код, вам потрібно оголосити остаточний лічильник в c # перед початком циклу.


11

Для того , щоб зробити приклад більш зрозумілим, я конвертувати як для петель в C # в той час як петля .

VB.NET

string stringValue = "42";

int min = 1;
int max = 10 - stringValue.Length;
int i = min;
while (i <= max)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

C #

string stringValue = "42";

int i = 1;
while (i <= 10 - stringValue.Length)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

Тоді різниця полягає в:

VB.NET кешує максимальне значення для i, але C # кожного разу перераховує його.


2
Вам не потрібно перетворювати цикли на while
Panagiotis Kanavos,

10
Це допомогло мені зрозуміти це for loopsз мого початку, я думаю, вони набагато зрозуміліші. Ось чому я "переклав" приклади while loops, щоб допомогти зрозуміти.
Максим Рекуерда,

7

Оскільки forin VB є іншою семантикою, ніж forC # (або будь-яка інша C-подібна мова)

У VB forвираз конкретно збільшує лічильник від одного значення до іншого.

У C, C ++, C # та ін. forВираз просто обчислює три вирази:

  • Перший вираз зазвичай є ініціалізацією
  • Другий вираз обчислюється на початку кожної ітерації, щоб визначити, чи виконано умову терміналу
  • Третій вираз обчислюється в кінці кожної ітерації, яка зазвичай є інкрементером.

У VB ви повинні надати числову змінну, яку можна перевірити на відповідність терміналу та збільшити на кожній ітерації

У C, C ++, C # тощо т. Вирази мінімально обмежені; умовний вираз повинен мати значення true / false (або ціле число нуль / ненуль у C, C ++). Вам зовсім не потрібно виконувати ініціалізацію, ви можете перебирати будь-який тип за будь-яким діапазоном значень, перебирати вказівник чи посилання на складну структуру або взагалі нічого не перебирати.

Отже, в C # тощо вираз умови повинен бути повністю оцінений на кожній ітерації, але в VB кінцеве значення ітератора має бути оцінене на початку, і його не потрібно оцінювати знову.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.