มีความแตกต่างอย่างมีนัยสำคัญระหว่างการใช้ if / else และ switch-case ใน C # หรือไม่?


219

ประโยชน์ / ข้อเสียของการใช้switchคำสั่งเทียบกับข้อif/elseใน C # คืออะไร ฉันไม่สามารถจินตนาการได้ว่ามันมีความแตกต่างอย่างมากนอกเหนือไปจากโค้ดของคุณ

มีเหตุผลใดบ้างที่ทำให้ IL ที่ได้หรือประสิทธิภาพรันไทม์ที่เกี่ยวข้องนั้นแตกต่างกันอย่างสิ้นเชิง?

ที่เกี่ยวข้อง: อะไรคือเร็วกว่าเปิดสตริหรืออื่น ๆ ในประเภท?


หัวข้อที่เกี่ยวข้อง: stackoverflow.com/questions/335971/is-switch-case-always-wrong
John T

3
คำถามนี้น่าสนใจในทางทฤษฎีสำหรับนักพัฒนาส่วนใหญ่เท่านั้นเว้นแต่คุณจะพบว่าตัวเองซ้ำหนึ่งพันล้านครั้ง (จากนั้นใช้คำสั่ง switch และเปลี่ยนจาก 48 เป็น 43 วินาที ... ) หรือในคำพูดของ Donald Knuth: "เราควรลืมประสิทธิภาพเล็กน้อยพูด 97% ของเวลา: การปรับให้เหมาะสมก่อนกำหนดเป็นรากของความชั่วร้ายทั้งหมด" en.wikipedia.org/wiki/Program_optimization#When_to_optimize
ฝ่าบาท

ฉันมักจะใช้ถ้า / อื่นแทนการเปลี่ยนเนื่องจากการกำหนดขอบเขตการแบ่งสวิตช์ที่สับสน
Josh

คำตอบ:


341

คำสั่ง SWITCH จะสร้างแอสเซมบลีเดียวกับ IF ในโหมดดีบักหรือความเข้ากันได้เท่านั้น ในการเปิดตัวมันจะถูกรวบรวมไว้ในตารางกระโดด (ผ่านคำสั่ง 'สวิตช์' ของ MSIL) - ซึ่งก็คือ O (1)

C # (ซึ่งแตกต่างจากภาษาอื่น ๆ ) ยังอนุญาตให้เปิดใช้ค่าคงที่สตริง - และสิ่งนี้ทำงานแตกต่างกันเล็กน้อย เห็นได้ชัดว่าไม่ได้มีประโยชน์ในการสร้างตารางกระโดดสำหรับสตริงที่มีความยาวตามอำเภอใจดังนั้นส่วนใหญ่สวิตช์ดังกล่าวจะถูกรวบรวมไว้ในสแต็กของ IF

แต่ถ้าจำนวนเงื่อนไขมีขนาดใหญ่พอที่จะครอบคลุมค่าใช้จ่ายคอมไพเลอร์ C # จะสร้างวัตถุ HashTable เติมด้วยค่าคงที่สตริงและทำการค้นหาบนตารางนั้นตามด้วยการกระโดด การค้นหา Hashtable นั้นไม่ใช่ O (1) และมีค่าใช้จ่ายคงที่ที่สังเกตได้ แต่ถ้าจำนวนของ case label มีขนาดใหญ่มันจะเร็วกว่าการเปรียบเทียบกับค่าคงที่ของสตริงใน IF

เพื่อสรุปให้ดีขึ้นถ้าจำนวนของเงื่อนไขมากกว่า 5 หรือมากกว่านั้นให้เลือก SWITCH มากกว่า IF หรือใช้สิ่งที่ดูดีกว่า


1
คุณแน่ใจหรือว่าผู้แปล C # จะสร้างตารางแฮช? จุดที่ฉันทำเกี่ยวกับตารางแฮชในการสนทนาความคิดเห็นของเราด้านบนคือเกี่ยวกับคอมไพเลอร์ดั้งเดิมไม่ใช่คอมไพเลอร์ C # คอมไพเลอร์ C # ใช้เกณฑ์อะไรในการสร้างตารางแฮช
Scott Wisniewski

8
ฉันคิดว่าประมาณสิบ 20 ที่จะอยู่ในด้านความปลอดภัย และ btw ความโกรธของฉันไม่ได้เป็นคุณ แต่สำหรับคนที่กำลังลุกฮือและยอมรับ
ima

48
การทดลองเล็กน้อยแนะนำให้นับ <= 6: "if"; นับ> = 7: พจนานุกรม นั่นคือคอมไพเลอร์ MS .NET 3.5 C # - มันสามารถเปลี่ยนระหว่างเวอร์ชั่นและผู้ขายได้แน่นอน
Jon Skeet

37
เฮ้ฉันขอโทษคุณ ขอโทษที่เป็นหัวหน้ากระดูก
Scott Wisniewski

ในการติดตามการใช้งานจริงมีความแตกต่างของโลกแห่งความเป็นจริงหรือไม่? ฉันพบว่า switch statement ใน C # เป็นเลขคี่, ไวยากรณ์ของพวกเขาไม่เหมือนอย่างอื่นและฉันพบว่าพวกเขาทำให้โค้ดของฉันอ่านได้น้อยลง, มันคุ้มค่าที่จะต้องใช้คำสั่ง switch, หรือฉันควรโปรแกรมด้วย ifs อื่น ๆ ย้อนกลับและแทนที่พวกเขาหากฉันไปถึงคอขวดของประสิทธิภาพหรือไม่
Jason Masters

54

โดยทั่วไป (พิจารณาจากทุกภาษาและคอมไพเลอร์ทั้งหมด) คำสั่ง switch สามารถบางครั้งมีประสิทธิภาพมากกว่าคำสั่ง if / else เพราะมันง่ายสำหรับคอมไพเลอร์ในการสร้างตารางกระโดดจากคำสั่งสวิตช์ มันเป็นไปได้ที่จะทำสิ่งเดียวกันสำหรับคำสั่ง if / else ที่ได้รับข้อ จำกัด ที่เหมาะสม แต่นั่นยากกว่ามาก

ในกรณีของ C # สิ่งนี้ก็เป็นจริงเช่นกัน แต่ด้วยเหตุผลอื่น

ด้วยสตริงจำนวนมากจึงมีความได้เปรียบด้านประสิทธิภาพที่สำคัญในการใช้คำสั่ง switch เนื่องจากคอมไพเลอร์จะใช้ตารางแฮชเพื่อใช้การข้าม

ด้วยสตริงจำนวนน้อยประสิทธิภาพระหว่างสองจะเหมือนกัน

นี่เป็นเพราะในกรณีนั้นคอมไพเลอร์ C # ไม่ได้สร้างตารางการกระโดด แต่จะสร้าง MSIL ที่เทียบเท่ากับ IF / ELSE block

มีคำสั่ง "คำสั่ง switch" MSIL ซึ่งเมื่อ jitted จะใช้ตารางกระโดดเพื่อนำคำสั่ง switch ใช้ได้กับประเภทจำนวนเต็มเท่านั้น (คำถามนี้ถามเกี่ยวกับสตริง)

สำหรับสตริงจำนวนน้อยจะมีประสิทธิภาพมากขึ้นสำหรับคอมไพเลอร์ในการสร้างบล็อก IF / ELSE จากนั้นจะใช้ตารางแฮช

เมื่อตอนแรกที่ฉันสังเกตเห็นสิ่งนี้ฉันทำข้อสันนิษฐานว่าเนื่องจากบล็อก IF / ELSE ถูกใช้กับสตริงจำนวนเล็กน้อยคอมไพเลอร์ทำการแปลงแบบเดียวกันสำหรับสตริงจำนวนมาก

นี่มันผิด 'IMA' ใจดีมากพอที่จะชี้ให้ฉันเห็น (อืม ... เขาไม่ได้ใจดี แต่เขาพูดถูกและฉันผิดซึ่งเป็นส่วนสำคัญ)

ฉันยังได้ตั้งสมมติฐานเกี่ยวกับการขาดคำสั่ง "สวิตช์" ใน MSIL (ฉันคิดว่าถ้ามีสวิตช์ดั้งเดิมทำไมพวกเขาไม่ใช้กับตารางแฮชดังนั้นจึงต้องไม่มีสวิตช์ดั้งเดิม ... ) นี่เป็นทั้งความผิดและโง่อย่างไม่น่าเชื่อในส่วนของฉัน 'IMA' อีกครั้งชี้ให้ฉันเห็น

ฉันอัปเดตที่นี่เพราะเป็นโพสต์ที่ได้รับคะแนนสูงสุดและเป็นคำตอบที่ยอมรับได้

อย่างไรก็ตามฉันได้ทำให้ชุมชน Wiki เพราะฉันคิดว่าฉันไม่สมควรได้รับตัวแทนสำหรับการที่ผิด หากคุณมีโอกาสโปรดโพสต์โพสต์ของ 'ima'


3
มีสวิตช์ดั้งเดิมใน MSIL และคำสั่ง c # รวบรวมไว้ในการค้นหาแบบ C โดยทั่วไป ภายใต้สถานการณ์บางอย่าง (แพลตฟอร์มเป้าหมายสวิตช์ cl ฯลฯ ) อาจถูกขยายเข้าไปใน IFs ในระหว่างการรวบรวม แต่เป็นเพียงการวัดความเข้ากันได้ทางเลือก
ima

6
ทั้งหมดที่ฉันทำได้คือขอโทษที่ทำผิดพลาด เชื่อฉันฉันรู้สึกเป็นใบ้เกี่ยวกับเรื่องนี้ แม้ว่าอย่างจริงจังฉันคิดว่ามันยังคงเป็นคำตอบที่ดีที่สุด เป็นไปได้ในคอมไพเลอร์เนทีฟที่จะใช้ตารางแฮชเพื่อทำการกระโดดดังนั้นนี่ไม่ใช่สิ่งที่ผิดอย่างน่ากลัว ฉันทำผิดพลาดครั้งเดียว
Scott Wisniewski

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

2
@Scott: ฉันขอแนะนำให้คุณแก้ไขย่อหน้าที่สองและสามเพื่อระบุ "สตริง" อย่างชัดเจน ผู้คนอาจไม่ได้อ่านการอัปเดตที่ด้านล่าง
Jon Skeet

4
@ima หากคุณคิดว่าคำตอบไม่ถูกต้องควรแก้ไขให้ถูกต้อง นั่นเป็นเหตุผลที่ทุกคนสามารถแก้ไขคำตอบได้
Miles Rout

18

สามเหตุผลที่ชอบswitch:

  • ที่กำหนดเป้าหมายรหัสพื้นเมืองมักจะสามารถรวบรวมงบเปลี่ยนให้เป็นคอมไพเลอร์สาขาเงื่อนไขหนึ่งบวกกระโดดทางอ้อมในขณะที่ลำดับของifs ต้องมีลำดับของสาขาเงื่อนไข ขึ้นอยู่กับความหนาแน่นของกรณีเอกสารจำนวนมากที่เรียนรู้ได้ถูกเขียนเกี่ยวกับวิธีรวบรวมคำสั่งกรณีอย่างมีประสิทธิภาพ บางส่วนมีการเชื่อมโยงจากหน้าคอมไพเลอร์ LCC (Lcc มีหนึ่งในคอมไพเลอร์ที่เป็นนวัตกรรมสำหรับสวิตช์)

  • คำสั่ง switch เป็นตัวเลือกระหว่างทางเลือกที่ไม่เหมือนกันและไวยากรณ์ของสวิตซ์ทำให้การควบคุมการไหลของข้อมูลมีความโปร่งใสมากขึ้นต่อโปรแกรมเมอร์จากนั้นรังของคำสั่ง if-then-else

  • ในบางภาษารวมถึง ML และ Haskell แน่นอนคอมไพเลอร์จะตรวจสอบเพื่อดูว่าคุณมีกรณีใดบ้างหรือไม่ ฉันมองว่าคุณสมบัตินี้เป็นหนึ่งในข้อได้เปรียบที่สำคัญของ ML และ Haskell ฉันไม่รู้ว่า C # สามารถทำได้หรือไม่

เรื่องเล็ก ๆ น้อย: ในการบรรยายที่เขาได้รับรางวัลสำหรับความสำเร็จตลอดชีวิตฉันได้ยิน Tony Hoare พูดว่าทุกสิ่งที่เขาทำในอาชีพของเขามีสามสิ่งที่เขาภาคภูมิใจที่สุด:

  • ประดิษฐ์ Quicksort
  • การประดิษฐ์คำสั่ง switch (ซึ่ง Tony เรียกว่าcaseคำสั่ง)
  • เริ่มต้นและสิ้นสุดอาชีพของเขาในอุตสาหกรรม

ฉันไม่สามารถจินตนาการได้โดยไม่ต้องอาศัยอยู่switch


16

คอมไพเลอร์จะปรับทุกอย่างให้เป็นโค้ดเดียวกันโดยมีความแตกต่างเล็กน้อย (Knuth, any?)

ความแตกต่างคือคำสั่งสวิทช์นั้นสะอาดกว่าสิบห้าถ้าหากมีข้อความอื่นมารวมกัน

เพื่อน ๆ จะไม่ปล่อยให้เพื่อนสแตกถ้า - อื่นงบ


13
"เพื่อนจะไม่ปล่อยให้เพื่อนสแตกถ้าคำสั่งอื่น" คุณควรทำ sitcker ที่ยุ่งเหยิง :)
Matthew M. Osborn

14

จริง ๆ แล้ว switch statement นั้นมีประสิทธิภาพมากกว่า คอมไพเลอร์จะปรับให้เหมาะสมกับตารางค้นหาที่มีคำสั่ง if / else ไม่สามารถทำได้ ข้อเสียคือไม่สามารถใช้คำสั่ง switch กับค่าตัวแปรได้
คุณทำไม่ได้:

switch(variable)
{
   case someVariable
   break;
   default:
   break;
}

มันจะต้องเป็น

switch(variable)
{
  case CONSTANT_VALUE;
  break;
  default:
  break;
}

1
คุณมีตัวเลขแบบไหนบ้าง? ฉันอยากรู้ว่าคอมไพเลอร์สามารถปรับคำสั่ง swtich ให้ดีขึ้นสำหรับ If / Else ได้อย่างไร
Matthew M. Osborn

ใช่ฉันเชื่อว่าคำสั่ง switch จะปรับให้เหมาะสมกับ O (1) โดยที่คำสั่ง if else จะเป็น O (n) โดยที่ n คือตำแหน่งของค่าที่ถูกต้องในคำสั่ง if / else ถ้า
kemiller2002

ในกรณีของ C # สิ่งนี้ไม่เป็นความจริงโปรดดูโพสต์ของฉันด้านล่างสำหรับข้อมูลเพิ่มเติม
Scott Wisniewski

ฉันไม่แน่ใจทั้งหมด แต่ฉันไม่สามารถหาข้อมูลในหนังสือที่ฉันสาบานได้ฉันพบมันคุณแน่ใจหรือว่าคุณไม่ได้ดูรหัส MSIL โดยไม่มีการเพิ่มประสิทธิภาพ มันจะไม่สร้างตารางการกระโดดเว้นแต่ว่าคุณจะรวบรวมการเพิ่มประสิทธิภาพ
kemiller2002

ฉันรวบรวมในโหมด debug และ retail และในทั้งสองกรณีมันสร้าง if / else บล็อก คุณแน่ใจหรือว่าหนังสือที่คุณกำลังดูกำลังพูดถึง C # อยู่ หนังสือเล่มนี้น่าจะเป็นหนังสือรวบรวมหรือหนังสือเกี่ยวกับ C หรือ C ++
Scott Wisniewski

14

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

ตัวอย่างเช่น:

if (x==0) then {
  // do one thing
} else if (x==1) {
  // do the other thing
} else if (x==2) {
  // do the third thing
}

VS

switch(x) {
  case 0: 
         // do one thing
         break;
  case 1: 
         // do the other thing
         break;
  case 2: 
         // do the third thing
         break;
}

หาก x เท่ากับศูนย์ 90% ของเวลารหัส "if-else" อาจเร็วเป็นสองเท่าของรหัสที่ใช้สวิตช์ แม้ว่าคอมไพเลอร์เปลี่ยน "สวิทช์" ให้กลายเป็น goto ที่ขับเคลื่อนด้วยตารางบางชนิดมันก็ยังไม่เร็วเท่าการตรวจสอบศูนย์


3
ไม่มีการเพิ่มประสิทธิภาพก่อนวัยอันควร! โดยทั่วไปหากคุณมีมากกว่าสองสามกรณีและพวกเขา - switchเข้ากันได้switchคำสั่งจะดีกว่า (อ่านง่ายขึ้นบางครั้งเร็วขึ้น) หากคุณรู้ว่ากรณีหนึ่งมีโอกาสมากขึ้นคุณสามารถดึงมันออกมาเพื่อสร้างif- else- switchและถ้ามันวัดได้เร็วกว่าคุณปล่อยให้มันเข้ามา (ทำซ้ำถ้าจำเป็น) IMO ที่ยังอ่านได้โดยมีเหตุผล หากความswitchเสื่อมโทรมและเล็กเกินไป regex-replace จะทำงานส่วนใหญ่ในการแปลงให้เป็นelse if-chain
ไม่มีใคร

6
คำถามเดิม (สามปีที่แล้ว!) เพิ่งถามถึงข้อดีและข้อเสียระหว่าง if / else และ switch นี่คือตัวอย่างหนึ่ง ฉันได้เห็นการเพิ่มประสิทธิภาพแบบนี้เป็นการส่วนตัวสร้างความแตกต่างอย่างมีนัยสำคัญในรันไทม์ของรูทีน
Mark Bessey

7

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

ดังนั้นหาก if / else ดูดีขึ้นให้ใช้มันมิฉะนั้นให้ใช้คำสั่ง switch


4

หัวข้อด้านข้าง แต่ฉันมักจะกังวลเกี่ยวกับ (และบ่อยขึ้นเห็น) if/ elseและswitchคำสั่งได้รับวิธีที่มีขนาดใหญ่เกินไปกับกรณีมากเกินไป สิ่งเหล่านี้มักจะทำร้ายการบำรุงรักษา

ผู้ร้ายทั่วไป ได้แก่ :

  1. ทำมากเกินไปภายในของหลาย ๆ คำสั่งถ้า
  2. งบกรณีมากกว่ามนุษย์เป็นไปได้ในการวิเคราะห์
  3. มีเงื่อนไขมากเกินไปในการประเมินถ้าหากรู้ว่ากำลังมองหาอะไรอยู่

เพื่อแก้ไข:

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

4

ตามลิงก์นี้IF vs Switchเปรียบเทียบการทดสอบการวนซ้ำโดยใช้สวิตช์และถ้ามีการใช้คำสั่งนั้นจะมีค่า 1,000,000,000 ซ้ำ, เวลาที่ใช้โดยคำชี้แจงสวิตช์ = 43.0s & โดยหากคำชี้แจง = 48.0s

ซึ่งแท้จริงแล้วคือ20833333การทำซ้ำต่อวินาทีดังนั้นหากเราต้องการที่จะมุ่งเน้นมากขึ้น

PS: เพียงเพื่อทราบความแตกต่างของประสิทธิภาพสำหรับรายการเงื่อนไขขนาดเล็ก


เล็บนั่นสำหรับฉัน
Greg Gum

3

หากคุณเพียงแค่ใช้ if หรือคำสั่งอื่น ๆ โซลูชันพื้นฐานกำลังใช้การเปรียบเทียบ ผู้ประกอบการ

(value == value1) ? (type1)do this : (type1)or do this;

คุณสามารถทำหรือกิจวัตรประจำวันในสวิตช์

switch(typeCode)
{
   case TypeCode:Int32:
   case TypeCode.Int64:
     //dosomething here
     break;
   default: return;
}

2

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

หากความตั้งใจของคุณคือการแยกโปรแกรมของคุณตามค่าของตัวแปร / คุณลักษณะหนึ่งคำสั่ง switch จะแสดงถึงความตั้งใจนั้นได้ดีที่สุด

หากความตั้งใจของคุณคือการแยกสาขาโปรแกรมของคุณตามตัวแปร / คุณสมบัติ / เงื่อนไขที่แตกต่างกันดังนั้นถ้า / อื่นถ้าเชนแสดงถึงความตั้งใจนั้นได้ดีที่สุด

ฉันจะให้โคดี้นั้นถูกต้องเกี่ยวกับคนที่ลืมคำสั่ง break แต่เกือบเท่าที่ฉันเห็นคนทำซับซ้อนหากบล็อกที่พวกเขาได้รับ {} ผิดดังนั้นบรรทัดที่ควรอยู่ในคำสั่งแบบมีเงื่อนไขไม่ได้ เป็นหนึ่งในเหตุผลที่ฉันมักจะรวม {} ไว้ในข้อความสั่งของฉันแม้ว่าจะมีหนึ่งบรรทัดในนั้น ไม่เพียง แต่จะง่ายต่อการอ่าน แต่ถ้าฉันต้องการเพิ่มอีกบรรทัดในเงื่อนไขฉันไม่สามารถลืมเพิ่มได้


2

คำถามที่น่าสนใจ สิ่งนี้เกิดขึ้นเมื่อไม่กี่สัปดาห์ที่ผ่านมาในที่ทำงานและเราพบคำตอบด้วยการเขียนตัวอย่างและดูใน. NET Reflector (reflector is Awesome !! i love it)

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

หากคุณต้องการเปรียบเทียบขนาดตัวพิมพ์เล็กและตัวใหญ่คุณสามารถใช้คำสั่ง switch ได้เร็วกว่าการใช้งาน String หากเปรียบเทียบกับ if / else (แก้ไข: อ่านอะไรที่เร็วกว่าเปิดสตริคหรือประเภทอื่นสำหรับการทดสอบประสิทธิภาพจริง ๆ ) อย่างไรก็ตามหากคุณต้องการใช้ตัวพิมพ์เล็กและตัวพิมพ์เล็กควรใช้ if / else เนื่องจากรหัสผลลัพธ์นั้นไม่สวย

switch (myString.ToLower())
{
  // not a good solution
}

กฎที่ดีที่สุดของ thumb คือการใช้คำสั่ง switch หากเหมาะสม (จริงจัง) เช่น:

  • มันปรับปรุงการอ่านรหัสของคุณ
  • คุณกำลังเปรียบเทียบช่วงของค่า (float, int) หรือ enum

หากคุณต้องการปรับเปลี่ยนค่าให้ฟีดลงในคำสั่ง switch (สร้างตัวแปรชั่วคราวเพื่อสลับค่า) จากนั้นคุณอาจจะใช้คำสั่งควบคุม if / else

การปรับปรุง:

มันเป็นจริงดีกว่าที่จะแปลงสตริงเป็นตัวพิมพ์ใหญ่ (เช่นToUpper()) ToLower()ในฐานะที่ได้รับการเห็นได้ชัดว่ามีการเพิ่มประสิทธิภาพต่อไปว่าคอมไพเลอร์เพียงในเวลาที่สามารถทำตามที่เมื่อเปรียบเทียบกับ มันเป็นการเพิ่มประสิทธิภาพขนาดเล็ก แต่ในวงแคบ ๆ มันอาจมีประโยชน์


หมายเหตุเล็กน้อย:

เพื่อปรับปรุงความสามารถในการอ่านของ switch statement ลองปฏิบัติดังนี้:

  • ใส่สาขาที่มีโอกาสมากที่สุดก่อนเช่นเข้าถึงได้มากที่สุด
  • หากพวกเขามีแนวโน้มที่จะเกิดขึ้นให้ระบุไว้ตามลำดับตัวอักษรเพื่อให้ง่ายต่อการค้นหา
  • ไม่เคยใช้ catch-all เริ่มต้นสำหรับเงื่อนไขสุดท้ายที่เหลืออยู่นั่นคือสันหลังยาวและจะทำให้เกิดปัญหาในภายหลังในชีวิตของรหัส
  • ใช้ค่าเริ่มต้น catch-all เพื่อยืนยันเงื่อนไขที่ไม่รู้จักแม้ว่าจะไม่เกิดขึ้นอย่างมาก นั่นคือสิ่งที่ยืนยันดีสำหรับ

ในหลายกรณีการใช้ ToLower () เป็นวิธีการแก้ปัญหาที่ถูกต้องโดยเฉพาะอย่างยิ่งหากมีหลายกรณีและตารางแฮชจะถูกสร้างขึ้น
Blaisorblade

"หากคุณต้องการปรับเปลี่ยนค่าฟีดลงในคำสั่ง switch (สร้างตัวแปรชั่วคราวเพื่อสลับค่า) จากนั้นคุณอาจจะใช้คำสั่งควบคุม if / else" - คำแนะนำที่ดีขอบคุณ
ส่อเสียด

2

คำสั่ง switch นั้นเร็วกว่าและถ้าเป็นอย่างอื่นแน่นอน มีการทดสอบความเร็วที่จัดทำโดย BlackWasp

http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx

- ตรวจสอบมัน

แต่ขึ้นอยู่กับความเป็นไปได้ที่คุณพยายามจะทำ แต่ฉันพยายามใช้คำสั่ง switch ทุกครั้งที่ทำได้


1

ไม่ใช่แค่ C # แต่ทุกภาษาที่ใช้ C ฉันคิดว่า: เนื่องจากสวิตช์ถูก จำกัด อยู่ที่ค่าคงที่จึงเป็นไปได้ที่จะสร้างรหัสที่มีประสิทธิภาพมากโดยใช้ "ตารางกระโดด" เคส C เป็นฟอร์แทรนเก่าที่คำนวณได้ดีของ GOTO แต่กรณี C # ยังคงทดสอบกับค่าคงที่

ไม่ใช่ในกรณีที่เครื่องมือเพิ่มประสิทธิภาพจะสามารถสร้างรหัสเดียวกันได้ พิจารณาเช่น

if(a == 3){ //...
} else if (a == 5 || a == 7){ //...
} else {//...
}

เพราะสิ่งเหล่านั้นเป็นสารประกอบบูลีนรหัสที่สร้างขึ้นจึงต้องคำนวณค่าและวงจรสั้น พิจารณาสิ่งที่เทียบเท่า

switch(a){
   case 3: // ...
    break;
   case 5:
   case 7: //...
    break;
   default: //...
}

สิ่งนี้สามารถรวบรวมได้

BTABL: *
B3:   addr of 3 code
B5:
B7:   addr of 5,7 code
      load 0,1 ino reg X based on value
      jump indirect through BTABL+x

เพราะคุณบอกคอมไพเลอร์ว่าไม่จำเป็นต้องคำนวณ OR และการทดสอบความเท่าเทียมกัน


ไม่มีเหตุผลที่เครื่องมือเพิ่มประสิทธิภาพที่ดีไม่สามารถจัดการรหัสที่ 1 ได้ตราบใดที่มีการใช้งานเครื่องมือเพิ่มประสิทธิภาพ "คอมไพเลอร์ไม่สามารถปรับให้เหมาะสม" เพียงแค่ขึ้นอยู่กับความแตกต่างทางความหมายซึ่งมีเพียงมนุษย์เท่านั้นที่สามารถกระทบยอดได้ (เช่นถ้าเรียกว่า f () ไม่ทราบว่า f () ส่งคืน 0 หรือ 1 เสมอ
Blaisorblade

0

อาจารย์ cs ของฉันไม่แนะนำให้คุณเปลี่ยนคำแถลงเพราะบ่อยครั้งที่คนลืมการพักหรือใช้อย่างไม่ถูกต้อง ฉันจำไม่ได้ว่าเขาพูดอะไร แต่มีบางอย่างตามเส้นที่มองที่ฐานรหัส seminal ที่แสดงตัวอย่างของคำสั่ง switch (ปีที่แล้ว) มีข้อผิดพลาดมากมายเช่นกัน


ไม่ใช่ปัญหาจริงๆใน C # ดู: stackoverflow.com/questions/174155/... ... และยังอ่านstackoverflow.com/questions/188461/...สำหรับการอภิปรายเกี่ยวกับเหตุผลที่มีชีวิตอยู่ในความหวาดกลัวไม่อาจจะเป็นนโยบายที่ดีที่สุด ...
Shog9

0

สิ่งที่ฉันเพิ่งสังเกตเห็นคือคุณสามารถรวม if / else และเปลี่ยน statement! มีประโยชน์มากเมื่อต้องตรวจสอบเงื่อนไขเบื้องต้น

if (string.IsNullOrEmpty(line))
{
    //skip empty lines
}
else switch (line.Substring(0,1))
{
    case "1":
        Console.WriteLine(line);
        break;
    case "9":
        Console.WriteLine(line);
        break;
    default:
        break;
}

3
ฉันรู้ว่ามันเก่า แต่ฉันคิดว่าในทางเทคนิคคุณไม่ได้ "รวม" อะไรเลย เมื่อใดก็ตามที่คุณมี "อื่น ๆ " โดยไม่มีวงเล็บปีกกาคำสั่งถัดไปจะถูกดำเนินการ คำสั่งนั้นอาจเป็นคำสั่งหนึ่งบรรทัดโดยทั่วไปแล้วจะแสดงการเยื้องในบรรทัดถัดไปหรือคำสั่งรวมเช่นกรณีที่มีถ้าสลับใช้ล็อค ฯลฯ ในคำอื่น ๆ คุณสามารถมี "อื่นถ้า", " else switch "," else using "ฯลฯ เมื่อบอกว่าฉันชอบรูปลักษณ์และความตั้งใจ (ข้อจำกัดความรับผิดชอบ: ฉันไม่ได้ลองสิ่งเหล่านี้ทั้งหมดดังนั้นฉันอาจผิดไปได้!)
เนลสันรอเธอร์เมล

เนลสันคุณถูกต้อง 100% ฉันคิดว่าทำไมสิ่งนี้เกิดขึ้นหลังจากฉันโพสต์คำตอบนี้
แม้เมี่ยน

0

ฉันคิดว่าสวิตช์นั้นเร็วกว่าหากเงื่อนไขดูว่ามีโปรแกรมเช่น:

เขียนโปรแกรมเพื่อป้อนหมายเลขใด ๆ (ระหว่าง 1 - 99) และตรวจสอบว่ามันอยู่ในช่องไหน a) 1 - 9 จากนั้นสล็อตหนึ่ง b) 11 - 19 จากนั้นสล็อตสอง c) 21-29 จากนั้นสล็อตสามถึง 89- 99

ถ้าอย่างนั้นคุณจะต้องทำหลายเงื่อนไข แต่ลูกชายเปลี่ยนกรณีที่คุณต้องพิมพ์

สวิตช์ (ไม่ / 10)

และในกรณีที่ 0 = 1-9, กรณีที่ 1 = 11-19 และอื่น ๆ

มันจะง่ายมาก

มีอีกหลายตัวอย่างเช่น!


0

คำสั่ง switch โดยพื้นฐานคือการเปรียบเทียบความเท่าเทียมกัน เหตุการณ์แป้นพิมพ์มีข้อได้เปรียบเหนือคำสั่งสวิตช์เมื่อมีการเขียนและอ่านรหัสได้ง่ายและถ้ามีคำสั่ง if หากไม่มี {Bracket} ก็อาจทำให้เกิดปัญหาได้เช่นกัน

char abc;
switch(abc)
{
case a: break;
case b: break;
case c: break;
case d: break;
}

คำสั่ง ifif ถ้ายอดเยี่ยมสำหรับโซลูชันมากกว่าหนึ่งวิธีถ้า (theAmountOfApples มากกว่า 5 && theAmountOfApples น้อยกว่า 10) บันทึกแอปเปิ้ลของคุณเป็นอย่างอื่นถ้า (theAmountOfApples == 100) ขายแอปเปิ้ลของคุณ ฉันไม่ได้เขียน c # หรือ c ++ แต่ฉันเรียนรู้มาก่อนที่ฉันจะเรียนรู้ java และพวกเขาเป็นภาษาที่ใกล้เคียง


0

ข้อเสียที่เป็นไปได้ข้อหนึ่งของคำสั่งสวิตช์คือการขาดเงื่อนไขหลายข้อ คุณสามารถมีหลายเงื่อนไขสำหรับ if (อื่น ๆ ) แต่ไม่ได้มีหลายกรณีที่มีเงื่อนไขต่างกันในสวิตช์

คำสั่ง Switch ไม่เหมาะสำหรับการดำเนินการทางตรรกะเกินขอบเขตของสมการ / นิพจน์บูลีนแบบง่าย สำหรับสมการบูลีน / นิพจน์นั้นจะเหมาะสมอย่างเห็นได้ชัด แต่ไม่ใช่สำหรับการดำเนินการเชิงตรรกะอื่น ๆ

คุณมีอิสระมากขึ้นด้วยตรรกะที่มีอยู่ในคำสั่ง If แต่ความสามารถในการอ่านอาจประสบได้หากคำสั่ง If กลายเป็นเรื่องไม่สะดวกหรือมีการจัดการที่ไม่ดี

ทั้งสองมีสถานที่ขึ้นอยู่กับบริบทของสิ่งที่คุณเผชิญ

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