Dlaczego pętla for zachowuje się inaczej podczas migracji kodu VB.NET do C #?


87

Jestem w trakcie migracji projektu z Visual Basic do C # i musiałem zmienić sposób fordeklarowania używanej pętli.

W VB.NET forpętla jest zadeklarowana poniżej:

Dim stringValue As String = "42"

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

Które wyjścia:

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

W C # forpętla jest zadeklarowana poniżej:

string stringValue = "42";

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

A wynik:

42 1
42 1 2
42 1 2 3

To oczywiście nie jest poprawne, więc musiałem nieznacznie zmienić kod i dołączyć zmienną całkowitą, która utrzymywałaby długość ciągu.

Zobacz poniższy kod:

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

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

A wynik:

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

Teraz moje pytanie dotyczy tego, jak Visual Basic różni się od C # pod względem Visual Basic przy użyciu stringValue.Lengthwarunku w forpętli, mimo że za każdym razem, gdy występuje pętla, zmienia się długość ciągu. Natomiast w C #, jeśli używam warunku stringValue.Lengthw forpętli, zmienia on początkową wartość ciągu za każdym razem, gdy występuje pętla. Dlaczego to?


7
Microsoft jasno przedstawia twój problem ...
Codexer

39
@ Çöđěxěŕ: Przestań, proszę. Gdyby pomocne było automatyczne usuwanie tagów z tytułu bez względu na kontekst, witryna by to zrobiła.
Ry-

11
@ Çöđěxěŕ Możesz znaleźć trochę informacji na ten temat tutaj
pushkin

35
@ Çöđěxěŕ Nie sądzę, że te dwa posty są ze sobą sprzeczne. Chodzi o to: nie przyklejaj niezręcznie w tytule tagu typu „pytanie o tę rzecz - tag”. Ale jeśli tytuł jest pełnym zdaniem, które zawiera tag, czasami jest w porządku. „Dlaczego pętla for zachowuje się inaczej podczas migracji” wydaje się zbyt ogólnikowym tytułem.
puszkin

26
@ Çöđěxěŕ „migracja kodu VB.NET do C #” to wyraźnie pełna fraza, która dodaje przydatne informacje do tytułu. Nie wprowadzaj zmian, które zmniejszają przejrzystość. Miejmy nadzieję, że ten pogląd jest na tyle zdrowy, że nie potrzebujemy postu w Meta, aby go poprzeć.
jpmc26

Odpowiedzi:


115

W języku C # warunek brzegowy pętli jest oceniany przy każdej iteracji. W VB.NET jest oceniany tylko przy wejściu do pętli.

Tak więc w wersji C # w pytaniu, ponieważ długość stringValuejest zmieniana w pętli, ostateczna wartość zmiennej pętli zostanie zmieniona.

W VB.NET ostateczny warunek jest włącznie, więc <=zamiast <w C # należy go używać .

Ocena warunku końcowego w C # ma taki wniosek, że nawet jeśli nie zmienia się, ale jest kosztowna do obliczenia, to powinna zostać obliczona tylko raz przed pętlą.


Dziękuję za odpowiedź. Teraz zdaję sobie sprawę, że używanie <=pozwala mi na iterację i daje takie same wyniki, jak kod VB. Jednak bardziej interesuje mnie, dlaczego musiałem zadeklarować zmienną całkowitą, a VBnie musiałem tego robić. Zamierzam zaktualizować moje pytanie, aby wyświetlało ten sam wynik.
slee423

@ slee423 Powód jest podany w pierwszym zdaniu mojej odpowiedzi. Ponieważ stringValuew pętli zmienia się długość , ostateczna wartość zmiennej pętli zostanie zmieniona.
Andrew Morton,

1
przepraszam, dziękuję za odpowiedź. Dziękuję za bardziej szczegółowe wyjaśnienie.
slee423

1
@ slee423 Dodałem to do odpowiedzi, ponieważ rzeczywiście to wyjaśnia.
Andrew Morton

22

Teraz moje pytanie dotyczy tego, w jaki sposób VB różni się od C # pod względem VB przy użyciu warunku stringValue.Length w pętli for, mimo że za każdym razem, gdy występuje pętla, zmienia się długość ciągu.

Zgodnie z dokumentacją VB.NET :

Jeśli zmienisz wartość counterwhile wewnątrz pętli, kod może być trudniejszy do odczytania i debugowania. Zmiana wartości start, endlub stepnie ma wpływu na wartość iteracji, które zostały ustalone, gdy pętla została po raz pierwszy wprowadzona.

Tak więc wartość To 10 - stringValue.Lengthjest obliczana raz i ponownie używana do zakończenia pętli.

Jednak spójrz na C # dla instrukcji

Jeśli for_conditionnie istnieje lub jeśli wynik oceny daje true, kontrola jest przenoszona do instrukcji osadzonej. Kiedy i jeśli sterowanie osiągnie punkt końcowy instrukcji osadzonej (prawdopodobnie z wykonania instrukcji continue), wyrażenia for_iterator, jeśli istnieją, są oceniane w kolejności, a następnie wykonywana jest kolejna iteracja, zaczynając od oceny instrukcji for_conditionw kroku powyżej.

Co w zasadzie oznacza, że ​​warunek ; i <= 10 - stringValueLength;jest oceniany ponownie za każdym razem.

Tak więc, jak widziałeś, jeśli chcesz zreplikować kod, musisz zadeklarować końcowy licznik w języku c # przed uruchomieniem pętli.


11

Aby uczynić przykład bardziej zrozumiałym, przekonwertuję obie pętle for na pętle while w języku 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++;
}

DO#

string stringValue = "42";

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

Różnica jest zatem taka:

VB.NET buforuje maksymalną wartość dla i, ale C # przelicza ją za każdym razem.


2
Nie musisz konwertować pętli na while
Panagiotis Kanavos

10
Pomogło mi to zrozumieć for loopsna początku, myślę, że są one dużo bardziej zrozumiałe. Dlatego „przetłumaczyłem” przykłady w języku while loops, aby ułatwić zrozumienie.
Maxime Recuerda

7

Ponieważ forin VB jest inną semantyczną niż forin C # (lub jakikolwiek inny język podobny do C)

W języku VB forinstrukcja zwiększa wartość licznika z jednej wartości do drugiej.

W językach C, C ++, C # itp. forInstrukcja po prostu ocenia trzy wyrażenia:

  • Pierwsze wyrażenie to zwykle inicjalizacja
  • Drugie wyrażenie jest oceniane na początku każdej iteracji, aby określić, czy warunek końcowy został spełniony
  • Trzecie wyrażenie jest oceniane na końcu każdej iteracji, które zwykle jest jednostką zwiększającą.

W VB musisz podać zmienną numeryczną, którą można przetestować względem wartości końcowej i zwiększać przy każdej iteracji

W językach C, C ++, C # itd. Te trzy wyrażenia są ograniczone w minimalnym stopniu; wyrażenie warunkowe musi mieć wartość prawda / fałsz (lub liczbę całkowitą zero / niezerową w C, C ++). Nie musisz w ogóle wykonywać inicjalizacji, możesz iterować dowolny typ w dowolnym zakresie wartości, iterować wskaźnik lub odwołanie po złożonej strukturze lub w ogóle nie wykonywać iteracji.

Tak więc w C # itd. Wyrażenie warunku musi być w pełni ocenione w każdej iteracji, ale w VB wartość końcowa iteratora musi zostać oszacowana na początku i nie musi być oceniana ponownie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.