web-dev-qa-db-ja.com

VB.NETコードをC#に移行するときにforループが異なる動作をするのはなぜですか?

私はプロジェクトを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

今度は、ループが発生するたびに文字列の長さが変わるにもかかわらず、forループでstringValue.Length条件を使用して、Visual BasicがVisual BasicとC#とでどのように異なるのかについて説明します。 C#では、forループ条件でstringValue.Lengthを使用すると、ループが発生するたびに初期ストリング値が変更されます。どうしてこれなの?

86
slee423

C#では、ループ境界条件は反復ごとに評価されます。 VB.NETでは、それはループへの入り口でのみ評価されます。

そのため、問題のC#バージョンでは、ループ内でstringValueの長さが変更されているため、最終的なループ変数の値が変更されます。

VB.NETでは、最終条件は包括的なので、C#では<=の代わりに<を使用します。

C#での終了条件の評価には当然の結果がありますが、たとえそれが変化しなくても計算するのに費用がかかるとしても、ループの前に一度だけ計算するべきです。

115
Andrew Morton

今度は、ループが発生するたびに文字列の長さが変化しても、forループでstringValue.Length条件を使用することでVBがVBの観点でC#とどう違うかを解決します。

VB.NET のドキュメントによると、

ループ内でcounterの値を変更すると、コードの読み取りやデバッグが困難になる可能性があります。 startend、またはstepの値を変更しても、ループに最初に入ったときに決定された反復値には影響しません。

そのため、To 10 - stringValue.Lengthの値は一度評価され、ループが終了するまで再利用されます。

しかし、 c#のステートメントを見てください

for_conditionが存在しない場合、または評価の結果がtrueの場合、制御は埋め込み文に移ります。制御が埋め込み文の終了点に達すると(おそらくcontinue文の実行から)、for_iteratorの式がある場合はそれが順番に評価され、次にfor_conditionの評価から始めて別の反復が実行されます。上記のステップ.

これは基本的に、条件; i <= 10 - stringValueLength;が毎回再度評価されることを意味します。

そのため、コードを複製したい場合は、ループを開始する前にc#で最後のカウンターを宣言する必要があります。

22

例をわかりやすくするために、両方のをループに変換してC#にします。 whileループします

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.NETiの最大値をキャッシュしますが、C#はそれを再計算します毎回。

10
Maxime Recuerda

VBのforは、C#(または他のC言語のような言語)のforとは異なる意味を持つためです。

VBでは、forステートメントはカウンタをある値から別の値へと具体的にインクリメントしています。

C、C++、C#などでは、forステートメントは単純に3つの式を評価します。

  • 最初の式は習慣的に初期化です
  • 2番目の式は各反復の開始時に評価されて、終了条件が満たされたかどうかを判断します。
  • 3番目の式は各反復の終わりに評価されます。これは通常インクリメンターです。

VBでは、あなたは終端値に対してテストされ、各反復で増加することができる数値変数を供給しなければなりません

C、C++、C#などでは、3つの式の制約は最小限です。条件式は真/偽(またはC、C++では整数のゼロ/非ゼロ)に評価される必要があります。初期化を実行する必要はまったくありません。任意の範囲の値に対して任意の型を反復したり、複雑な構造体に対してポインタまたは参照を反復したり、まったく何も反復しないことができます。

そのため、C#などでは、条件式は各反復で完全に評価される必要がありますが、VBでは、反復子の終端値は最初に評価される必要があり、再度評価する必要はありません。

7
C Robinson