18

C# では (他の言語については自由に回答してください)、ランタイムはどのような順序で論理ステートメントを評価しますか?

例:

DataTable myDt = new DataTable();
if (myDt != null && myDt.Rows.Count > 0)
{
    //do some stuff with myDt
}

ランタイムが最初に評価するステートメント -

myDt != null

また:

myDt.Rows.Count > 0

?

コンパイラがステートメントを逆方向に評価するときはありますか? おそらく、「OR」演算子が関係しているときですか?


& はビット単位の論理演算子として知られており、常にすべての部分式を評価します。

「短絡ブール値」の代わりにビットごとの演算子を使用する場合の良い例は何ですか?

4

18 に答える 18

16

C# : 左から右へ、一致しない (false と評価される) 場合は処理が停止します。

于 2008-08-07T20:33:22.847 に答える
9

「C# : 左から右へ、一致する (true と評価される) 場合は処理が停止します。」

ゾンビ羊は間違っています。反対票を投じるには十分な担当者がいません。

問題は、|| ではなく && 演算子に関するものです。オペレーター。

&& の場合、FALSE が見つかった場合は評価が停止します。

||の場合 TRUE が見つかった場合、評価は停止します。

于 2008-08-08T06:51:14.283 に答える
8

この質問は既に回答済みですが、このトピックに関連する別の情報を追加したいと思います。

C++ などの言語では、&& と || の動作を実際にオーバーロードできます。これを行わないことを強くお勧めします。これは、この動作をオーバーロードすると、操作の両側の評価が強制されるためです。これにより、次の 2 つのことが行われます。

  1. オーバーロードは呼び出す必要がある関数であるため、遅延評価メカニズムが壊れます。したがって、関数を呼び出す前に両方のパラメーターが評価されます。
  2. 上記のパラメーターの評価の順序は保証されておらず、コンパイラー固有である可能性があります。したがって、オブジェクトは、質問/前の回答にリストされている例と同じようには動作しません。

詳細については、Scott Meyers の著書「More Effective C++ 」をお読みください。乾杯!

于 2008-08-07T22:23:56.057 に答える
6

vb.net

if( x isNot Nothing AndAlso x.go()) then
  1. 評価は左から右に行われます
  2. AndAlso演算子は、左側が TRUE の場合にのみ右側が評価されるようにします (非常に重要です。ifx は何もないため、x.go はクラッシュします)。

vb では、AndAlso の代わりにAndを使用できます。この場合、左側も最初に評価されますが、結果に関係なく右側が評価されます。

ベスト プラクティス: 非常に正当な理由がない限り、常に AndAls を使用してください。


フォローアップで、AndAlso の代わりに (または && の代わりに & を) And を使用する理由または時期について尋ねられました。 以下に例を示します。

if ( x.init() And y.init()) then
   x.process(y)
end 
y.doDance()

この場合、X と Y の両方を初期化します。y.DoDance を実行できるようにするには、Y を初期化する必要があります。ただし、init() 関数では、ソケットが開いていることを確認するなどの追加のことも行っています。

繰り返しますが、これはおそらく 99% のケースでは不要であり、洗練されていません。そのため、デフォルトでAndAlsoを使用する必要があると言ったのです。

于 2008-08-07T20:35:11.657 に答える
5

@shsteimer

謙虚さが言及している概念は、オペレーターのオーバーロードです。... A が最初に評価され、false と評価された場合、B は評価されません。同じことが当てはまります

それは演算子のオーバーロードではありません。演算子のオーバーロードは、*、+、= などの演算子のカスタム動作を定義できるようにするための用語です。

これにより、独自の「ログ」クラスを作成してから実行できます

a = new Log(); // Log class overloads the + operator
a + "some string"; // Call the overloaded method - otherwise this wouldn't work because you can't normally add strings to objects.

これを行う

a() || b() // be never runs if a is true

実際には短絡評価と呼ばれます

于 2008-08-07T21:58:21.723 に答える
4

ZombieSheep は必死です。待っているかもしれない唯一の「落とし穴」は、これは && 演算子を使用している場合にのみ当てはまるということです。& 演算子を使用すると、一方または両方が false に評価されるかどうかに関係なく、両方の式が毎回評価されます。

if (amHungry & whiteCastleIsNearby)
{
   // The code will check if White Castle is nearby
   // even when I am not hungry
}

if (amHungry && whiteCastleIsNearby)
{
   // The code will only check if White Castle is nearby
   // when I am hungry
}
于 2008-08-07T20:45:43.273 に答える
4

&& と & には、式のどの程度が評価されるかに関して違いがあることに注意してください。

&& は短絡ブール AND として知られており、ここで他の人が指摘したように、すべての部分式が評価される前に結果が決定できる場合は早期に停止します。

& はビット単位の論理演算子として知られており、常にすべての部分式を評価します。

そのような:

if (a() && b())

aがtrueを返す場合にのみbを呼び出します。

ただし、これ:

if (a() & b())

a を呼び出した結果が false であるため、 bを呼び出した結果に関係なくfalseであることがわかっている場合でも、常にabの両方を呼び出します。

|| にも同じ違いがあります。と | オペレーター。

于 2008-08-07T20:52:27.440 に答える
4

一部の言語では、式が異なる順序で実行される興味深い状況があります。私は特に Ruby を考えていますが、他の場所 (おそらく Perl) から借用したに違いありません。

ロジック内の式は左から右にとどまりますが、たとえば次のようになります。

puts message unless message.nil?

上記は「message.nil?」を評価します。最初に、それが false と評価された場合 (条件が true ではなく false の場合に if except が実行される場合を除く)、「puts message」が実行され、メッセージ変数の内容が画面に出力されます。

これは、コードを構成する興味深い方法です... 個人的には、上記のような非常に短い 1 ライナーに使用するのが好きです。

編集:

少しわかりやすくするために、上記は次と同じです。

unless message.nil?
  puts message
end
于 2008-08-07T20:54:51.897 に答える
2

左のものは、null の場合は停止します。

編集:vb.netでは、AndAlsoを使用しない限り、両方を評価し、エラーをスローする可能性があります

于 2008-08-07T20:31:32.973 に答える
2

謙虚さが言及している概念は、オペレーターのオーバーロードです。声明で:

if( A && B){
    // do something
}

A が最初に評価され、false と評価された場合、B は評価されません。同じことが当てはまります

if(A || B){
    //do something
}

A が最初に評価され、true と評価された場合、B は評価されません。

このオーバーロードという概念は、(私が思うに) すべての C スタイル言語に適用され、他の多くの言語にも適用されます。

于 2008-08-07T20:35:32.437 に答える
1

いいえ、少なくともC#コンパイラは逆方向には機能しません(&&または||のいずれかで)。左から右です。

于 2008-08-07T21:00:27.473 に答える
1

「短絡ブール値」の代わりにビットごとの演算子を使用する場合の良い例は何ですか?

ファイル属性などのフラグがあるとします。READ を 4、WRITE を 2、EXEC を 1 と定義したとします。バイナリでは、次のようになります。

READ  0100  
WRITE 0010  
EXEC  0001

各フラグには 1 つのビット セットがあり、それぞれが一意です。ビット演算子を使用すると、これらのフラグを組み合わせることができます。

flags = READ & EXEC; // value of flags is 0101
于 2008-08-07T21:51:00.757 に答える
1

すべてがインラインの場合、左から右に実行されます。

物事が入れ子になっている場合、それらは内側から外側へと実行されます。通常、「最も内側」のものは線の右側にあるため、これは混乱するように見えるかもしれません。そのため、逆方向に進んでいるように見えます...

例えば

a = Foo( 5, GetSummary( "Orion", GetAddress("Orion") ) );

物事は次のように起こります:

  • GetAddressリテラルで呼び出す"Orion"
  • GetSummaryリテラル"Orion"との結果で呼び出すGetAddress
  • Fooリテラル5との結果で呼び出すGetSummary
  • この値をに割り当てますa
于 2008-08-07T22:02:36.583 に答える
1

私はオリオンの反応が好きです。2 つのことを追加します。

  1. 左から右が最初に適用されます
  2. 関数を呼び出す前にすべての引数が解決されていることを確認するための inner-to-outer

次の例があるとします。

a = Foo(5, GetSummary("Orion", GetAddress("Orion")),
           GetSummary("Chris", GetAddress("Chris")));

実行順序は次のとおりです。

  1. GetAddress("Orion")
  2. GetSummary("Orion", ...)
  3. GetAddress("Chris")
  4. GetSummary("Chris", ...)
  5. Foo(...)
  6. に割り当てますa

C# の法的要件について話すことはできませんが (この投稿を書く前に、Mono を使用して同様の例をテストしましたが)、この順序は Java で保証されています。

また、完全を期すために (これも言語に依存しないスレッドであるため)、C や C++ などの言語では、シーケンス ポイントがない限り順序が保証されません。参考文献: 1 , 2 . ただし、スレッドの質問に答える&&||、C++ のシーケンス ポイントになります (オーバーロードされていない限り、OJ の優れた回答も参照してください)。いくつかの例:

  • foo() && bar()
  • foo() & bar()

この&&場合、はシーケンス ポイントであるため、foo()前に実行されることが保証されますbar()(後者が実行される場合) 。&&その&場合、そのような保証は (C および C++ では) 行われず、実際に のbar()前に実行することfoo()も、その逆も可能です。

于 2008-08-07T22:33:16.833 に答える
0

@csmba

フォローアップで、なぜ、いつ誰かがAndAlsoの代わりにAndを使用するのか(または&&の代わりに&を使用するのか)を尋ねられました。例を次に示します。

if ( x.init() And y.init()) then
   x.process(y)
end 
y.doDance()

この場合、XとYの両方を初期化します。y.DoDanceを実行できるようにするには、Yを初期化する必要があります。ただし、init()関数では、ソケットが開いていることを確認するなどの追加の処理も行っています。それがうまくいく場合にのみ、両方について、先に進んでx.process(y)を実行する必要があります。

これはかなり紛らわしいと思います。あなたの例は機能しますが、それは使用するための典型的なケースではありませんAnd(そして私はおそらくこれをより明確にするために別の方法で書くでしょう)。And&他のほとんどの言語では)実際にはビット単位の演算です。これを使用して、ビット演算を計算します。たとえば、フラグビットを削除したり、フラグをマスキングしてテストしたりします。

Dim x As Formatting = Formatting.Bold Or Formatting.Italic
If (x And Formatting.Italic) = Formatting.Italic Then
    MsgBox("The text will be set in italic.")
End If
于 2008-08-20T07:35:22.897 に答える
0

コンパイラが逆方向に動作するとどこかで聞いたことがありますが、これがどの程度正しいかはわかりません。

于 2008-08-07T20:34:11.800 に答える
0

すべての部分式を具体的に評価したい場合は & を使用します。これは、最終結果がfalseになり、 ifステートメントのthen部分を実行しない場合でも、必要な副作用がある可能性が最も高いためです。

& と | に注意してください。ビット単位のマスクとブール値の両方で動作し、ビット単位の操作だけではありません。これらはビットごとに呼び出されますが、C# では整数とブール データ型の両方に対して定義されています。

于 2008-08-07T22:01:24.493 に答える
0

D プログラミング言語は、ショート サーキットを使用して左から右への評価を行い、および '||' のオーバーロードを許可しません。オペレーター。&&

于 2010-04-14T22:49:01.210 に答える