เหตุใดจึงมีทั้งการลัดวงจรหรือเช่นเดียวกับการเปลี่ยนแปลงที่ไม่ผ่านรอบของตัวดำเนินการนั้นใน C #


9

ฉันสงสัยเกี่ยวกับสิ่งนี้เป็นระยะ

การลัดวงจรหรือจะคืนค่าเดียวกันกับที่ตัวดำเนินการ OR ที่ไม่มีการลัดวงจรหรือ

ฉันคาดหวังว่าการลัดวงจรหรือจะประเมินผลเร็วกว่าเสมอ ดังนั้นตัวดำเนินการ OR ที่ไม่มีการลัดวงจรรวมอยู่ในภาษา C # เพื่อความมั่นคงหรือไม่

ฉันพลาดอะไรไป


9
ค่าส่งคืนเดียวกัน - ใช่ ผลข้างเคียงที่เหมือนกัน - ไม่
งาน

2
สมมติว่าf()ยกข้อยกเว้นพิจารณาและtrue || f() true | f()คุณเห็นความแตกต่างหรือไม่ การแสดงออกในอดีตประเมินไปที่trueการประเมินผลหลังในข้อยกเว้นที่ถูกโยน
Scarfridge

คำตอบ:


25

ตัวถูกดำเนินการทั้งสองนั้นมีความหมายสำหรับสิ่งต่าง ๆ มาจาก C ซึ่งไม่มีประเภทบูลีน รุ่นลัดวงจร || ใช้งานได้กับ booleans เท่านั้นในขณะที่รุ่น non-short circuit | ทำงานร่วมกับประเภทที่สำคัญการดำเนินการในระดับบิตหรือ มันเพิ่งจะเกิดขึ้นในการทำงานเป็นปฏิบัติการตรรกะไม่ลัดวงจรสำหรับบูลีนซึ่งจะแสดงเป็นบิตเดียวเป็น 0 หรือ 1

http://en.wikibooks.org/wiki/C_Sharp_Programming/Operators#Logical


10
+1 สำหรับลิงก์ เมื่อฉันอ่านคำถามนี้ฉันก็เหมือน "อะไรนะ" ตั้งแต่ afaik ชื่ออย่างเป็นทางการของเหล่านี้มีเหตุผลและ bitwise หรือและไม่ใช่การลัดวงจรและ unshort-circuit ซึ่งเกิดขึ้นกับผลข้างเคียงของการทำงาน
Stijn

1
+1 ฉันเห็น "ทำงานกับตัวถูกดำเนินการบูลีนเท่านั้น" - ฉันอาจไม่ได้สังเกตเห็นความแตกต่างเพราะฉันใช้เฉพาะนิพจน์ที่ประเมินเป็นบูลีนอยู่ดี
CarneyCode

2
ฉันได้ไปตรวจสอบ แต่ในความเป็นจริงความจริงที่ว่า|ผู้ประกอบการเมื่อนำไปใช้สองค่าบูลีนเรียบเรียงเดียวกันorผู้ประกอบการใน CIL มันเป็นเมื่อนำไปใช้สองค่าจำนวนเต็ม - แตกต่าง||ซึ่งเป็นเรียบเรียง CIL ใช้brtrueสำหรับเงื่อนไข กระโดด.
quentin-starin

13

|(ค่าบิตหรือ) intต้องไม่ลัดวงจรชนิดเช่น นั่นเป็นเพราะในเกือบทุกกรณีคุณจำเป็นต้องคำนวณทั้งสองด้านของ|นิพจน์เพื่อคำนวณผลลัพธ์ที่ถูกต้อง ตัวอย่างเช่นผลลัพธ์ของ7 | f(x)อะไร

หากf(x)ไม่ได้รับการประเมินคุณจะไม่สามารถบอกได้

นอกจากมันจะไม่สอดคล้องกันเพื่อให้การดำเนินการนี้ลัดวงจรสำหรับเมื่อมันไม่เป็นลัดวงจรสำหรับbool intโดยวิธีการที่ฉันคิดว่าฉันไม่เคยใช้|สำหรับการเปรียบเทียบเชิงตรรกะโดยจงใจพบว่ามันไม่สะดวกมากที่จะพูด|ว่าเป็นผู้ประกอบการเชิงตรรกะ

|| อย่างไรก็ตามสำหรับการเปรียบเทียบเชิงตรรกะที่การประเมินผลการลัดวงจรทำงานได้ดี

สิ่งเดียวกันนั้นใช้ได้แม้กับ C และ C ++ ซึ่งเป็นที่มาของตัวดำเนินการเหล่านั้น


5

สิ่งนี้ถูกต้องตัวดำเนินการลัดวงจรหรือ (||) จะส่งกลับค่าเดียวกันกับตัวดำเนินการที่ไม่ใช่ลัดวงจรหรือ (|) เสมอ (*)

อย่างไรก็ตามหากตัวถูกดำเนินการแรกเป็นจริงตัวดำเนินการลัดวงจรจะไม่ทำให้เกิดการประเมินตัวถูกดำเนินการตัวที่สองในขณะที่ตัวดำเนินการที่ไม่ใช่ลัดวงจรจะทำให้เกิดการประเมินตัวถูกดำเนินการทั้งสองเสมอ สิ่งนี้อาจส่งผลกระทบต่อประสิทธิภาพการทำงานและบางครั้งเกิดผลข้างเคียง

ดังนั้นจึงมีการใช้ทั้งสองอย่าง: ถ้าคุณสนใจประสิทธิภาพและการประเมินตัวถูกดำเนินการครั้งที่สองไม่ได้สร้างผลข้างเคียงใด ๆ (หรือถ้าคุณไม่สนใจพวกเขา) โดยวิธีทั้งหมดใช้ตัวดำเนินการลัดวงจร . แต่ถ้าด้วยเหตุผลบางอย่างที่คุณต้องการมีผลข้างเคียงของตัวถูกดำเนินการตัวที่สองดังนั้นคุณควรใช้ตัวดำเนินการที่ไม่ลัดวงจร

ตัวอย่างที่คุณควรใช้ตัวดำเนินการที่ไม่ลัดวงจร:

if( write_customer_to_database() != SUCCESS |
    write_supplier_to_database() != SUCCESS |
    write_order_to_database() != SUCCESS )
{
    transaction_rollback();
}

(*) ยกเว้นบางสถานการณ์ที่บิดเบือนซึ่งการประเมินตัวถูกดำเนินการครั้งแรกเป็นสาเหตุเท็จโดยผลข้างเคียงตัวถูกดำเนินการตัวที่สองเพื่อประเมินผลเป็นจริงแทนที่จะเป็นเท็จ


2
+1 แต่ฉันต้องการเพิ่มนอกเหนือจากการใช้ฟังก์ชั่นเพื่อบ่งชี้ความสำเร็จหรือความล้มเหลว (ตามตัวอย่างของคุณ): โดยทั่วไปแล้วควรหลีกเลี่ยงการใช้ฟังก์ชันที่มีผลข้างเคียง ...
Marjan Venema

1
ใช่นั่นอาจเป็นเหตุผลว่าทำไมฉันไม่เคยใช้ตัวดำเนินการที่ไม่ใช่ไฟฟ้าลัดวงจรมาจนถึงทุกวันนี้และมีโอกาสน้อยที่ฉันจะทำ
Mike Nakis

ตัวอย่างนั้นขึ้นอยู่กับตัวถูกดำเนินการที่ถูกประเมินตามลำดับจากซ้ายไปขวาอย่างเข้มงวด C # รับประกันสิ่งนี้ แต่ภาษาที่คล้ายกันจำนวนมาก (รวมถึง C และ C ++) ไม่ได้ทำ
Keith Thompson

การประเมินผลการลัดวงจรจะไม่สมเหตุสมผลสำหรับตัวอย่างเฉพาะนั้นเนื่องจากธุรกรรมทั้งหมดจะถูกย้อนกลับหากมีรายการใดล้มเหลว (ฉันกำลังตั้งสมมติฐานบางอย่างเกี่ยวกับความหมายของการโทร)
Keith Thompson

@ KeithThompson คุณถูกต้องการประเมินผลแบบไม่ลัดวงจรจะทำให้เกิดการประมวลผลที่ไม่จำเป็นและในกรณีนี้ตัวอย่างเป็นบิตง่อย write_customer_to_database () สำเร็จจากนั้นฟังก์ชั่นการเขียน _... ที่เหลือจะไม่ถูกเรียกใช้และจะเป็นการดีกว่าที่จะทำงานอย่างถูกต้องในกรณีที่ประสบความสำเร็จมากกว่าที่จะดำเนินการบางอย่างที่ไม่จำเป็นในกรณีที่เกิดความล้มเหลว
Mike Nakis

4

จะมี 2 เหตุผลในการใช้ชุดตัวเลือกที่ไม่ใช่วงจรสั้น:

  1. การรักษาผลข้างเคียง (แต่ชัดเจนกว่าการเขียนโค้ดด้วยตัวแปรชั่วคราว)

  2. ขัดขวางการโจมตีเวลาด้วยการหลีกเลี่ยงทางแยกในไฟฟ้าลัดวงจร (นี่อาจปรับปรุงประสิทธิภาพการรันไทม์หากตัวถูกดำเนินการตัวที่สองเป็นตัวแปร แต่นั่นคือการเพิ่มประสิทธิภาพขนาดเล็กที่คอมไพเลอร์อาจทำอยู่ดี)


นี่คือเหตุผลที่ถูกต้องเท่านั้นฉันไม่รู้ว่าทำไมนี่ไม่ใช่คำตอบที่ได้รับการยอมรับด้วยคะแนนโหวตสูงสุด ...
Behrooz

2

หากประโยคด้านขวาของผู้ปฏิบัติงานมีผลข้างเคียงและโปรแกรมเมอร์ตั้งใจว่าเขาต้องการให้เกิดผลข้างเคียงทั้งสองก่อนที่จะตรวจสอบค่าส่งคืน


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