หรือเทียบกับ OrElse


96

อะไรคือความแตกต่างระหว่างหรือกับOrElse ?

if temp is dbnull.value or temp = 0

สร้างข้อผิดพลาด:

Operator '=' ไม่ได้กำหนดไว้สำหรับประเภท 'DBNull' และประเภท 'Integer'

ในขณะที่ตัวนี้ใช้งานได้อย่างมีเสน่ห์!?

if temp is dbnull.value OrElse temp = 0

คำตอบ:


147

OrElseเป็นตัวดำเนินการลัดวงจรOrไม่ใช่

ตามคำจำกัดความของตัวดำเนินการบูลีน 'หรือ' ถ้าคำแรกเป็น True หมายความว่าทั้งหมดเป็นจริงแน่นอน - ดังนั้นเราไม่จำเป็นต้องประเมินพจน์ที่สอง

OrElseรู้สิ่งนี้ดังนั้นอย่าพยายามประเมินtemp = 0เมื่อได้รับการยอมรับแล้วtemp Is DBNull.Value

Orไม่ทราบเรื่องนี้และจะพยายามประเมินทั้งสองคำเสมอ เมื่อtemp Is DBNull.Valueเทียบกับศูนย์ไม่ได้ดังนั้นมันจึงล้มลง

คุณควรใช้ ... ดีอย่างใดอย่างหนึ่งที่เหมาะสม


2
ดังนั้นหรือสมเหตุสมผลเมื่อฉันเรียกใช้ฟังก์ชันหลังจากหรือที่มีผลข้างเคียงรหัสของฉันขึ้นอยู่กับ?
Ralph M. Rickenbach

4
หรือสมเหตุสมผลในทุกกรณีที่รายการที่สองไม่ทำให้เกิดข้อผิดพลาดหากรายการแรกเป็นจริง ...
awe

4
@ malach: ฉันคิดว่าอย่างนั้น (คุณได้รับพฤติกรรม OrElse เป็นค่าเริ่มต้นในภาษาอื่น ๆ ส่วนใหญ่) ไม่ควรเรียกใช้ฟังก์ชันที่มีผลข้างเคียงในเงื่อนไขแบบผสมซึ่งจะทำให้รหัสไม่สามารถอ่านได้
Utaal

4
@ awe: ใช่ แต่ทำไมคุณถึงต้องการเสียเวลาในการประเมินบางสิ่งซึ่งตามคำจำกัดความจะไม่เปลี่ยนผลลัพธ์ของนิพจน์?
Utaal

3
@MarkJ: ฉันไม่คิดว่าอักขระพิเศษสี่ตัวจะขัดขวางการอ่าน ในทางกลับกันการใช้ตัวดำเนินการที่ขึ้นอยู่กับการมีอยู่ของผลข้างเคียง (ตามที่ malach เขียนไว้) เพื่อให้ฟังดูมีความหมายเหมือนเป็นความคิดที่ไม่ดี (และทำให้อ่านได้ยากขึ้น!) ฉันคิดว่าผลข้างเคียงในสถานที่ดังกล่าวเป็นเรื่องใหญ่และไม่สามารถนึกถึงสถานการณ์ใด ๆ ที่ฉันต้องการ "หรือ" ถึง "OrElse" เป็นที่น่าเสียดายที่ตัวดำเนินการเหล่านี้ทำงานในลักษณะนี้เนื่องจากพฤติกรรม "OrElse" น่าจะเป็นสิ่งที่คาดหวังมากที่สุดแม้ว่าจะใช้ "หรือ" ก็ตาม (โดยเฉพาะเมื่อมาจากภาษาอื่น)
Kjartan

43

นี่เป็นพฤติกรรมเดียวกันกับ C # โดยที่ทุกคนใช้ Coditional Or (||) และ Conditional And (&&) โดยที่คุณมี Normal Or (|) และ Normal And (&) ดังนั้นการเปรียบเทียบ C # กับ VB.Net คือ:

| => หรือ

|| => OrElse

& => และ

&& => และนอกจากนี้

ตัวดำเนินการบูลีนแบบ condifitonal มีประโยชน์มากในการป้องกันไม่ให้ซ้อนกันหากมีการสร้าง แต่บางครั้งจำเป็นต้องใช้ตัวดำเนินการบูลีนปกติเพื่อให้แน่ใจว่าการกดปุ่มทั้งสองเส้นทางของรหัส


9
ฉันไม่เคยรู้มาก่อนว่ามีให้บริการ ขอบคุณสำหรับข้อมูลใหม่ นานาน่ารู้แม้ว่าฉันจะไม่เห็นสถานการณ์ที่ต้องการใช้ "|" ฉันคิดว่ามันจะต้องมีเงื่อนไขที่สองในการทำให้เกิดผลข้างเคียงจึงจะสมเหตุสมผลและในความคิดของฉันก็ไม่ค่อยมีเหตุผล! ;)
Kjartan

8
เอ๊ะเท่าที่ฉันรู้|และ&เป็นตัวดำเนินการระดับบิตใน C # ไม่ใช่การดำเนินการแบบบูลีนเลย
Nyerguds

8

OrElse ลัดวงจรซึ่งหมายความว่าจะมีการทดสอบเพียงด้านเดียวของนิพจน์หากด้านแรกตรงกัน

เช่นเดียวกับ AndAlso จะทดสอบเพียงด้านเดียวของนิพจน์หากครึ่งแรกล้มเหลว


4

(ฉันได้ดูคำตอบอื่น ๆ และตระหนักว่าฉันคิดผิดอย่างมาก)

โอเปอเรเตอร์ OrElse "ทำการลัดวงจรการแยกทางตรรกะบนสองนิพจน์" กล่าวคือถ้าตัวถูกดำเนินการด้านซ้ายเป็นจริงดังนั้นนิพจน์ทั้งหมดจะได้รับการรับรองว่าเป็นจริงตัวถูกดำเนินการที่ถูกต้องจะไม่ได้รับการประเมิน กรณีเช่น:

string a;
//...
if (a is null) or (a = "Hi") //...

เพื่อหลีกเลี่ยงการโยน NullReferenceException โดยตัวถูกดำเนินการทางขวามือ

ผมขอแสดงความนับถือประหลาดใจที่ว่านี้ ( การประเมินผลขี้เกียจ ) ไม่ทำงานเริ่มต้นของorและandเป็นอยู่ใน C / C ++ และ C # (และภาษาอื่น ๆ อีกมากมาย ... )


7
สิ่งนี้คือใน VB classic มีเพียง And และ Or ซึ่งไม่ลัดวงจร ฉันคิดว่าฉันพูดถูกแล้วว่า betas แรกของ VB.NET เปลี่ยนพฤติกรรมของตัวดำเนินการเหล่านี้ - มีความโกลาหลดังนั้นพวกเขาจึงถูกเปลี่ยนกลับและมีการแนะนำ AndAlso และ OrElse (การลัดวงจร) ฉันนึกออก แต่ชื่อทางเลือกที่พวกเขาต้องพิจารณาหากเป็นชื่อที่ดีที่สุด ...
AakashM

1
การระบุ Or และ OrElse (| และ || ใน C #) จะทำให้นักพัฒนาสามารถเลือกวิธีจัดการโค้ดของตนเองได้ เมื่อใช้โค้ดด้านบนฉันต้องใช้การลองจับรอบ ๆ เพื่อจัดการกับค่าว่างในตัวแปร a OrElse อนุญาตให้นักพัฒนาจัดการสิ่งนี้ในคำสั่งอื่นของ if โดยเป็นผลลัพธ์ที่เป็นไปได้ที่ทราบแล้วแทนที่จะเป็นข้อยกเว้น สิ่งนี้จะชัดเจนมากขึ้นหากตัวแปร a เป็นพารามิเตอร์ในวิธีการซึ่งคุณควบคุมได้น้อยลงเมื่อตัวแปรถูกกำหนดค่า (เช่นนอกวิธีการ)
Kevin Hogg

การลัดวงจรไม่ใช่พฤติกรรมเริ่มต้นของ OR และ AND ใน c # เช่นกัน c # มีตัวดำเนินการสองตัวที่แตกต่างกันสำหรับการดำเนินการในระดับบิตและตรรกะ / ลัดวงจร && และ || ทำการเปรียบเทียบเชิงตรรกะและส่งคืนค่าบูลีน The & and | ตัวดำเนินการเป็นบิตและส่งกลับค่าจำนวนเต็ม ดังนั้นโดยที่ 1 || 2 คืนค่า "จริง", 1 | 2 คืนค่า "3"
TomXP411

4

OrElse ประเมินนิพจน์แรกจากนั้นหากเป็นจริงจะดำเนินการต่อในคำสั่งในขณะที่ OR ประเมินสองนิพจน์ก่อนที่จะดำเนินการต่อไปยังคำสั่ง

ตัวอย่าง:

Textbox1.Text= 4

Textbox2.Text= ""

ใช้ OrElse

  If TextBox1.Text > 2 OrElse TextBox2.Text > 3 Then
      MsgBox("True")
  End If

ผลลัพธ์คือ: TRUE


ใช้ OR

 If TextBox1.Text > 2 Or TextBox2.Text > 3 Then

            MsgBox("True")
  End If

ผลลัพธ์คือ:ข้อผิดพลาดไม่สามารถแปลงสตริงเป็นสองเท่า


3

คำตอบของเบิร์ตไม่ถูกต้องมากนัก '|' หรือ '&' เป็นตัวดำเนินการเชิงตรรกะใน C # จะถือว่าเป็นตัวดำเนินการบิตเสมอโปรดดูรหัสต่อไปนี้เป็นตัวอย่าง

        static void Main()
        {
            object a = null;
            int b = 3;
            if (a == null | a.ToString() == "sdffd")
            {
                Console.WriteLine("dddd");
            }
            Console.WriteLine(b | b);
            Console.Read();
        }

ต่อไปนี้คือ IL

    .method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       62 (0x3e)
  .maxstack  3
  .locals init ([0] object a,
           [1] int32 b,
           [2] bool CS$4$0000)
   IL_0000:  nop
   IL_0001:  ldnull
   IL_0002:  stloc.0
   IL_0003:  ldc.i4.3
   IL_0004:  stloc.1
   IL_0005:  ldloc.0
   IL_0006:  ldnull
   IL_0007:  ceq
   IL_0009:  ldloc.0
   IL_000a:  callvirt   instance string [mscorlib]System.Object::ToString()
   IL_000f:  ldstr      "sdffd"
   IL_0014:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                 string)
   IL_0019:  or
   IL_001a:  ldc.i4.0
   IL_001b:  ceq
   IL_001d:  stloc.2
   IL_001e:  ldloc.2
   IL_001f:  brtrue.s   IL_002e
   IL_0021:  nop
   IL_0022:  ldstr      "dddd"
   IL_0027:  call       void [mscorlib]System.Console::WriteLine(string)
   IL_002c:  nop
   IL_002d:  nop
   IL_002e:  ldloc.1
   IL_002f:  ldloc.1
   IL_0030:  or
   IL_0031:  call       void [mscorlib]System.Console::WriteLine(int32)
   IL_0036:  nop
   IL_0037:  call       int32 [mscorlib]System.Console::Read()
   IL_003c:  pop
   IL_003d:  ret
    } // end of method Program::Main

เมื่อคุณใช้ || เพื่อทดสอบ "a == null" และ "a ToString () ==" sdffd "IL จะเป็น

 .method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       63 (0x3f)
  .maxstack  2
  .locals init ([0] object a,
           [1] int32 b,
           [2] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.3
  IL_0004:  stloc.1
  IL_0005:  ldloc.0
  IL_0006:  brfalse.s  IL_001d
  IL_0008:  ldloc.0
  IL_0009:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_000e:  ldstr      "sdffd"
  IL_0013:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                 string)
  IL_0018:  ldc.i4.0
  IL_0019:  ceq
  IL_001b:  br.s       IL_001e
  IL_001d:  ldc.i4.0
  IL_001e:  stloc.2
  IL_001f:  ldloc.2
  IL_0020:  brtrue.s   IL_002f
  IL_0022:  nop
  IL_0023:  ldstr      "dddd"
  IL_0028:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_002d:  nop
  IL_002e:  nop
  IL_002f:  ldloc.1
  IL_0030:  ldloc.1
  IL_0031:  or
  IL_0032:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0037:  nop
  IL_0038:  call       int32 [mscorlib]System.Console::Read()
  IL_003d:  pop
  IL_003e:  ret
} // end of method Program::Main

ตอนนี้คุณสามารถเห็นความแตกต่างได้โปรดอย่าคิดว่า '|' หรือ 'และ' เป็นตัวดำเนินการตามเงื่อนไขมันเป็นเพียงตัวดำเนินการเชิงตรรกะฉันไม่คิดว่าจำเป็นต้องใช้เพื่อตัดสินเงื่อนไข


2
The '|' or '&' is logical operator, in C #, it always treat as bit operator. ฉันก็เชื่อในสิ่งนี้เช่นกันจนกระทั่งฉันเห็นการอ้างอิงนี้msdn.microsoft.com/en-us/library/kxszd0kx.aspx
user3207158

คำตอบของคุณไม่อยู่ในบริบท คำถามไม่เกี่ยวข้องกับ C # แต่เป็น VB ที่ตัวดำเนินการทางตรรกะสี่ตัว: AndAlso, Or, OrElse, Not และ Xor เป็นตัวดำเนินการทางตรรกะและ Bitwise
Jean-François

0

เว้นแต่ว่าตรรกะรหัสของคุณต้องการพฤติกรรมการลัดวงจรที่ OrElse จัดเตรียมไว้ฉันจะเอนเอียงไปใช้ตัวดำเนินการหรือเนื่องจาก:

  • การใช้ "หรือ" เป็นเรื่องง่ายและต้องพิมพ์น้อยลง
  • การประหยัดเวลาในการคำนวณของการใช้ OrElse นั้นน้อยมากในกรณีส่วนใหญ่
  • สิ่งสำคัญที่สุดคือการใช้ OrElse สามารถซ่อนข้อผิดพลาดในส่วนคำสั่งในภายหลังซึ่งอาจไม่ได้รับการเปิดเผยในตอนแรกจนกว่าเงื่อนไขเหล่านั้นจะเป็นไปตามตรรกะของโปรแกรม

0

สาเหตุที่การคอมไพล์ล้มเหลวในตัวอย่างคือ ลำดับของการดำเนินการ

โปรแกรมแยกวิเคราะห์นิพจน์กำลังพยายามประเมิน "dbnull.value หรือ temp" ก่อน

if temp is (dbnull.value or temp) = 0

ข้อผิดพลาดอยู่ที่นี่เนื่องจากคุณไม่สามารถทำบิตหรือระหว่างจำนวนเต็ม (temp) และ dbnull.value ได้

OrElse แก้ไขปัญหานี้ไม่ใช่เพราะไฟฟ้าลัดวงจร แต่เป็นเพราะลำดับการทำงานต่ำกว่าดังนั้น "temp คือ dbnull.value" และ "3 = 0" จึงได้รับการประเมินก่อนแทนที่จะเป็นตัววิเคราะห์ที่พยายามเปรียบเทียบ dbNull และ อุณหภูมิ

ดังนั้นการประเมินด้วย OrElse จึงทำงานได้อย่างที่คุณคาดหวัง: (สมมติว่า temp = 3)

if temp is dbnull.value OrElse temp = 0 then
if 3 is dbnull.value OrElse 3 = 0 then
if false OrElse 3=0 then
if false OrElse false then
if false then

จริงๆแล้วนี่เป็นการสอบเข้า บริษัท ซอฟต์แวร์ที่ฉันเคยทำงานและเป็นปัญหาทั่วไปที่ฉันเคยพบใน VB6 ดังนั้นคุณควรวงเล็บนิพจน์ย่อยของคุณเมื่อใช้ตัวดำเนินการบูลีน:

สิ่งนี้จะได้รวบรวมอย่างถูกต้อง:

if (temp is dbnull.value) Or (temp = 0) then 

แม้ว่าตามที่ทุกคนได้ชี้ให้เห็นแล้ว OrElse และ AndAlso เป็นตัวดำเนินการที่ถูกต้องที่จะใช้ในบริบทนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.