21
4

10 に答える 10

43

DoSomething2 に設定すると、それらxは異なります。

于 2013-01-16T00:05:18.820 に答える
24
[STAThread]
public static void Main()
{
    Int32 x = 1;

    if (x == 1)
        Console.WriteLine("1");
    else if (x == 2)
        Console.WriteLine("2");
}

結果:

.method public hidebysig static void Main() cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 x)
    L_0000: ldc.i4.1 
    L_0001: stloc.0 
    L_0002: ldloc.0 
    L_0003: ldc.i4.1 
    L_0004: bne.un.s L_0011
    L_0006: ldstr "1"
    L_000b: call void [mscorlib]System.Console::WriteLine(string)
    L_0010: ret 
    L_0011: ldloc.0 
    L_0012: ldc.i4.2 
    L_0013: bne.un.s L_001f
    L_0015: ldstr "2"
    L_001a: call void [mscorlib]System.Console::WriteLine(string)
    L_001f: ret 
}

その間:

[STAThread]
public static void Main()
{
    Int32 x = 1;

    if (x == 1)
        Console.WriteLine("1");

    if (x == 2)
        Console.WriteLine("2");
}

結果:

.method public hidebysig static void Main() cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 x)
    L_0000: ldc.i4.1 
    L_0001: stloc.0 
    L_0002: ldloc.0 
    L_0003: ldc.i4.1 
    L_0004: bne.un.s L_0010
    L_0006: ldstr "1"
    L_000b: call void [mscorlib]System.Console::WriteLine(string)
    L_0010: ldloc.0 
    L_0011: ldc.i4.2 
    L_0012: bne.un.s L_001e
    L_0014: ldstr "2"
    L_0019: call void [mscorlib]System.Console::WriteLine(string)
    L_001e: ret 
}

IL コードは少し異なります。主な違いは次のとおりです。

Approach One: L_0004: bne.un.s L_0011 -> L_0011: ldloc.0 with L_0010: ret 
Approach Two: L_0004: bne.un.s L_0010 -> L_0010: ldloc.0 with no ret in between

最初のアプローチのようにelseステートメントを使用すると、条件に一致する最初のブランチのみが実行されます。一方... 2番目のアプローチでは、すべてのチェックが処理され、条件を満たすすべてのチェックが追跡されて処理されます。それが主な違いです。

そのため、最初のアプローチの IL コードでは、Console.WriteLine の呼び出しの直後に「ret」ディレクティブがあり、2 番目のアプローチでは存在しません。最初のケースでは、チェックが通過した直後にメソッドを終了できます。これ以上チェックxが実行されないためです... 2番目のアプローチでは、それらすべてを順番にたどる必要があるため、 ret はメソッド、最後まで「近道」はありません。

私のテストでは、Console.WriteLine()呼び出しを使用しました...しかし、変数DoSomething()の値の変更が含まれる場合x、コードの動作において違いが絶対に重要になることは確かです。ローカル変数ではなく、プライベートな静的メンバー (初期値は常に 1) として x があるとします。

public void DoSomething()
{
    ++m_X;
}

最初のアプローチでは、最初のチェックのおかげで が呼び出されたm_X後に値が 2 であると仮定しても、それ以外の場合はメソッドが終了し、呼び出されることはありません。2 番目のアプローチでは、両方のメソッドが呼び出されます。DoSomething()DoSomethingElse()

于 2013-01-16T00:27:06.483 に答える
14

else ifC# にはコンストラクトがないことに注意してください。最初のコード サンプルは次とまったく同じです。

if (x == 1)
    DoSomething();
else 
{
    if (x == 2)
        DoSomethingElse();
}

にはステートメントが 1 つしかないためelse、中かっこは省略できます。読みやすくするために、if通常は前の と同じ行に記述しelseます。複数の " else if" ステートメントを記述することは、さらにネストすることと同じです。

if (x == 1)
    DoSomething();
else 
{
    if (x == 2)
        DoSomethingElse();
    else
    {
        if (x == 3)
            YetSomethingElse();
        else
        {
            if (x == 4)
               ReallyDifferent();
        }
    }
}

上記は次のように記述できます。

if (x == 1)
    DoSomething();
else if (x == 2)
    DoSomethingElse();
else if (x == 3)
    YetSomethingElse();
else if (x == 4)
    ReallyDifferent();

このことから、チェーン " else if"ifが異なる結果を生成できることがわかります。" else if" の場合、条件を満たす最初の分岐が実行され、その後はそれ以上のチェックは行われません。連鎖ifステートメントの場合、条件を満たすすべての分岐が実行されます。

ここでの主な違いは、分岐の実行によって後続の条件が true になるタイミングです。例えば:

   var x = 1;

   if (x == 1)
       x = 2;
   else if (x == 2)
       x = 3;

VS

   var x = 1;

   if (x == 1)
       x = 2;

   if (x == 2)
       x = 3;

最初のケースでx == 2は 、2 番目のケースではx == 3.

于 2013-01-16T01:52:06.137 に答える
10

このようにコーディングすると

// approach two
if (x == 1)
    DoSomething();
if (x == 2)
    DoSomethingElse();

状態がチェックされるたびに。

しかし、このようにコーディングすると

if (x == 1)
    DoSomething();
else if (x == 2)
    DoSomethingElse();

最初の条件が true の場合、次の else if 条件をチェックしないため、不要なコンパイルが減少します。

于 2014-09-25T10:48:18.733 に答える
5

ステートメントを使用するelseと、分岐の 1 つだけが実行されます (つまり、if条件に一致する最初の分岐)。他のすべてのif条件は推定さえされません。

// approach one
int x = 1;
if (x == 1)
    DoSomething(); //only this will be run, even if `DoSomething` changes `x` to 2
else if (x == 2)
    DoSomethingElse();

使用しない場合は、(各条件に応じて) それぞれが実行される場合があります。つまり、それぞれが 1 つずつ推定されます。

// approach two
int x = 1;
if (x == 1)
    DoSomething();//this is run, as `x` == 1
if (x == 2)
    DoSomethingElse();//if `DoSomething` changes `x` to 2, this is run as well

そのため、IL は異なる場合があります。

于 2013-01-16T00:06:45.623 に答える
4

パフォーマンスに関する回答はありませんか?

したがって、x=1 の場合、最初のケースでは 1 つのチェックのみを実行し、2 番目のケースでは 2 つのチェックを実行するため、最初のケースの方が高速です。

于 2013-01-16T00:15:47.830 に答える
3

x が変更された場合 (Do Seomthing および DoSomethingElse で)、最初のステートメントは 1 つのステートメントのみを実行します。2 番目の例では、すべてのステートメントがチェックされます (もちろん、コンパイラが数値比較のためにジャンプ テーブルに最適化しない限り)。

于 2013-01-16T00:06:17.927 に答える
3

multiple を使用するelse ifと、条件を満たす条件を実行します。残りのケースがある場合、それらはスキップされます。が複数ifある場合は、すべてのステートメントをチェックします。したがって、これはパフォーマンスの問題になります。

于 2013-01-16T00:44:06.680 に答える
2

xが複数のスレッドによって変更された場合、2 番目のアプローチで と の両方が呼び出される可能性がDoSomething()ありますDoSomethingElse()

于 2013-01-16T00:06:40.400 に答える