การใช้การลองใช้ในที่สุด (ไม่จับ) vs การตรวจสอบความถูกต้องของ enum


9

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

ขึ้นเขียงของฉันในการปฏิบัติที่ดีที่สุดคือว่าควรใช้ลอง / catch / ในที่สุดเพื่อส่งกลับ enum (หรือ int ที่แสดงถึงค่า 0 สำหรับข้อผิดพลาด 1 สำหรับตกลง 2 สำหรับคำเตือน ฯลฯ ขึ้นอยู่กับกรณี)เพื่อให้ คำตอบอยู่ในระเบียบเสมอหรือควรให้ข้อยกเว้นดำเนินไปเพื่อที่ส่วนการเรียกจะจัดการกับมัน

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

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

แม้ว่าจะเป็นไปได้ที่จะลองจับข้อยกเว้น 404 ภายในฟังก์ชั่นตัวช่วยที่ได้รับ / โพสต์ข้อมูลคุณควรไหม มีเพียงฉันที่ใช้อักษรตัวเล็ก ๆ เพื่อแสดงสถานะในโปรแกรม (และจัดทำเอกสารอย่างเหมาะสม) แล้วใช้ข้อมูลนี้เพื่อจุดประสงค์ในการตรวจสอบความมีเหตุผล

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

อีกครั้งด้วย http get / post ตัวอย่างคำถามคือคุณควรให้วัตถุใหม่ที่อธิบายสิ่งที่เกิดขึ้นกับผู้โทรเดิมหรือไม่ หากผู้ช่วยนี้อยู่ในห้องสมุดที่คุณใช้อยู่คุณคาดว่าจะให้รหัสสถานะสำหรับการดำเนินการหรือคุณจะรวมไว้ในบล็อก try-catch หรือไม่ หากคุณกำลังออกแบบคุณจะให้รหัสสถานะหรือส่งข้อยกเว้นและให้ระดับบนแปลเป็นรหัสสถานะ / ข้อความแทนหรือไม่

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


1
ที่ไม่ได้จัดการกับข้อผิดพลาดที่เปลี่ยนรูปแบบของการจัดการข้อผิดพลาดที่ใช้ ในกรณี 404 คุณจะปล่อยให้มันผ่านเพราะคุณไม่สามารถจัดการได้
stonemetal

"int ที่แสดงถึงค่า 0 สำหรับข้อผิดพลาด 1 สำหรับตกลง 2 สำหรับคำเตือน ฯลฯ " โปรดบอกว่านี่เป็นตัวอย่างนอกข้อมือ! โดยใช้ค่าเฉลี่ย 0 ถึงตกลงเป็นอย่างมากแน่นอนมาตรฐาน ...
Anaximander

คำตอบ:


15

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

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

ไม่ควรใช้ข้อยกเว้นเพื่อใช้ตรรกะของโปรแกรม ในคำอื่น ๆ อย่าโยนข้อยกเว้นเพื่อทำให้เสร็จ ส่งข้อยกเว้นเพื่อระบุว่าไม่สามารถทำได้


ขอบคุณสำหรับการตอบกลับมันเป็นข้อมูลมากที่สุด แต่ฉันให้ความสำคัญกับการจัดการข้อยกเว้นไม่ใช่การโยนยกเว้น คุณควรตรวจจับข้อยกเว้น 404 ทันทีที่คุณได้รับมันหรือคุณควรปล่อยให้มันสูงขึ้นไปในกอง?
Mihalis Bagos

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

1
+1: สำหรับคำอธิบายที่สมเหตุสมผลและสมดุล ข้อยกเว้นควรใช้เพื่อจัดการกรณีพิเศษ มิฉะนั้นฟังก์ชันหรือเมธอดควรส่งคืนค่าที่มีความหมาย (enum หรือประเภทตัวเลือก) และผู้เรียกควรจัดการอย่างเหมาะสม อาจจะพูดถึงทางเลือกที่สามที่เป็นที่นิยมในการเขียนโปรแกรมการทำงานเช่นต่อเนื่อง
Giorgio

4

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

ตัวอย่างเช่น System.IO.File.OpenRead () จะโยน FileNotFoundException หากไฟล์ที่ให้มาไม่มีอยู่อย่างไรก็ตามยังมีเมธอด. Exists () ซึ่งส่งคืนค่าบูลีนที่ระบุว่าไฟล์นั้นมีอยู่หรือไม่ เรียก OpenRead () เพื่อหลีกเลี่ยงข้อยกเว้นที่ไม่คาดคิด

เพื่อตอบคำถาม "เมื่อไรที่ฉันควรจัดการกับข้อยกเว้น" ฉันจะพูดทุกที่ที่คุณสามารถทำอะไรกับมันได้ หากวิธีการของคุณไม่สามารถจัดการกับข้อยกเว้นที่เกิดจากวิธีการที่เรียกใช้อย่าจับมัน ปล่อยให้มันยกระดับสายโซ่โทรศัพท์ให้สูงขึ้นไปสู่สิ่งที่สามารถจัดการได้ ในบางกรณีนี่อาจเป็นเพียงคนตัดไม้ที่กำลังฟัง Application.UnhandledException


หลายคนโดยเฉพาะโปรแกรมเมอร์งูใหญ่ชอบEAFPนั่นคือ "มันง่ายกว่าที่จะขอการให้อภัยมากกว่าการขออนุญาต"
Mark Booth

1
+1 สำหรับความคิดเห็นเกี่ยวกับการหลีกเลี่ยงข้อยกเว้นเช่นเดียวกับ. Exists ()
codingoutloud

+1 นี่ยังเป็นคำแนะนำที่ดี ในรหัสที่ฉันเขียน / จัดการข้อยกเว้นคือ "เจ๋ง" 9/10 ครั้งที่ข้อยกเว้นมีไว้สำหรับนักพัฒนาที่จะเห็นมันบอกว่าเฮ้คุณควรจะเขียนโปรแกรม defensivley! อีกครั้งหนึ่งมันเป็นสิ่งที่เราไม่สามารถจัดการได้และเราบันทึกมันและออกไปให้ดีที่สุด ความสอดคล้องเป็นสิ่งสำคัญตัวอย่างเช่นโดยปกติแล้วเราจะมีการตอบโต้ที่ผิดจริงและข้อความภายในสำหรับค่าโดยสาร / การประมวลผลมาตรฐาน API ของบุคคลที่สามที่ดูเหมือนจะโยนข้อยกเว้นสำหรับทุกสิ่งสามารถจัดการได้ที่โทรและกลับมาโดยใช้กระบวนการมาตรฐานที่ตกลงกันไว้
Gavin Howden

3

ใช้ try / catch / สุดท้ายเพื่อส่งคืน enum (หรือ int ที่แทนค่า 0 สำหรับข้อผิดพลาด 1 สำหรับ ok, 2 สำหรับคำเตือน ฯลฯ ขึ้นอยู่กับกรณี) เพื่อให้คำตอบอยู่ในลำดับเสมอ

นั่นเป็นการออกแบบที่แย่มาก อย่า "ปกปิด" ข้อยกเว้นด้วยการแปลเป็นรหัสตัวเลข ปล่อยให้มันเป็นข้อยกเว้นที่เหมาะสมและไม่คลุมเครือ

หรือควรปล่อยให้ข้อยกเว้นผ่านเพื่อที่ส่วนการโทรจะจัดการกับมัน?

นั่นคือสิ่งที่ยกเว้นสำหรับ

จัดการกับใกล้กับที่จะยกขึ้นเป็นไปได้

ไม่ใช่ความจริงสากลเลย มันเป็นความคิดที่ดีบางครั้ง บางครั้งก็ไม่เป็นประโยชน์


มันไม่ใช่การออกแบบที่แย่มาก Microsoft ใช้งานในหลายสถานที่ซึ่ง ได้แก่ ผู้ให้บริการสมาชิก asp.net ที่เป็นค่าเริ่มต้น นอกจากนั้นฉันไม่เห็นว่าคำตอบนี้มีส่วนช่วยอะไรในการสนทนา
มิฮาลิสบาโกส

@MihalisBagos: ทั้งหมดที่ฉันทำได้คือแนะนำว่าวิธีการของ Microsoft ไม่ได้ครอบคลุมในทุกภาษาการเขียนโปรแกรม ในภาษาที่ไม่มีข้อยกเว้นการส่งคืนค่าเป็นสิ่งจำเป็น C เป็นตัวอย่างที่น่าสังเกตมากที่สุด ในภาษาที่มีข้อยกเว้นการส่งคืน "ค่าของโค้ด" เพื่อระบุข้อผิดพลาดเป็นการออกแบบที่แย่มาก มันนำไปสู่ifคำสั่งที่ยุ่งยาก (บางครั้ง) แทนที่จะจัดการได้ง่ายกว่า (บางครั้ง) คำตอบ ("วิธีการที่คุณเลือก ... ") นั้นง่ายมาก อย่า ฉันคิดว่าการพูดแบบนี้จะช่วยเพิ่มการสนทนา อย่างไรก็ตามคุณสามารถเพิกเฉยต่อคำตอบนี้ได้
S.Lott

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

1
ข้อยกเว้นนี้เป็นหมวดหมู่ / องค์กรแล้ว ฉันไม่เห็นค่าในการแทนที่ข้อยกเว้นที่ชัดเจนด้วยค่าส่งคืนที่อาจสับสนได้ง่ายกับค่าส่งคืน "ปกติ" หรือ "ไม่พิเศษ" ค่าส่งคืนควรไม่เป็นค่าที่ไม่เสมอไป ความคิดเห็นของฉันไม่ได้พัฒนามาก: มันง่ายมาก อย่าแปลงข้อยกเว้นเป็นรหัสตัวเลข มันเป็นวัตถุข้อมูลที่สมบูรณ์แบบซึ่งให้บริการทุกกรณีการใช้งานที่ดีอย่างสมบูรณ์แบบที่เราสามารถจินตนาการได้
S.Lott

3

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

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

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


1

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

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

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

ดังนั้นคำถามของฉันถึง OP คือเหตุผลที่คุณไม่ต้องการใช้ข้อยกเว้นในการส่งคืนรหัสข้อผิดพลาด


0

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

สิ่งนี้ทำให้นึกถึงกฎที่ดีในการใช้รหัสโดย:

บรรทัดของรหัสเป็นเหมือนสัญลักษณ์แสดงหัวข้อย่อยสีทอง คุณต้องการใช้ให้น้อยที่สุดเพื่อให้งานเสร็จ


0

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

ฉันยังใช้ประโยชน์จากการโยนข้อยกเว้นจะหยุดการดำเนินการเพราะฉันไม่ต้องการให้การดำเนินการต่อไปเมื่อข้อมูลไม่ถูกต้อง

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

procedure Validate(var R:TValidationRecord);
begin
  if Field1 is not valid then
  begin
    R.Field1ErrorCode=SomeErrorCode;
    ErrorFlag := True; 
  end; 
  if Field2 is not valid then
  begin
    R.Field2ErrorCode=SomeErrorCode;
    ErrorFlag := True; 
  end;
  if Field3 is not valid then
  begin
    R.Field3ErrorCode=SomeErrorCode;
    ErrorFlag := True; 
  end;

  if ErrorFlag then
    ThrowException
end;

หากอาศัยเพียงบูลีนเท่านั้นนักพัฒนาที่ใช้ฟังก์ชั่นของฉันควรคำนึงถึงเรื่องนี้เป็นลายลักษณ์อักษร:

if not Validate() then
  DoNotContinue();

แต่เขาอาจลืมและโทรออกเท่านั้นValidate()(ฉันรู้ว่าเขาไม่ควร แต่เขาอาจจะ)

ดังนั้นในรหัสข้างต้นฉันได้รับสองข้อได้เปรียบ:

  1. ข้อยกเว้นเดียวเท่านั้นในฟังก์ชันการตรวจสอบความถูกต้อง
  2. ข้อยกเว้นแม้ไม่ถูกจับจะหยุดการทำงานและปรากฏในเวลาทดสอบ

0

ไม่มีคำตอบเดียวที่นี่ - ประเภทของ HttpException นั้นไม่มีประเภทเดียวกัน

มันสมเหตุสมผลเป็นอย่างมากที่ไลบรารี่ HTTP พื้นฐานนั้นยกเว้นเมื่อได้รับการตอบสนองแบบ 4xx หรือ 5xx; ครั้งล่าสุดที่ฉันดูข้อมูลจำเพาะ HTTP ซึ่งเป็นข้อผิดพลาด

สำหรับการโยนข้อยกเว้นนั้น - หรือห่อมันแล้วทำการคิดใหม่ - ฉันคิดว่านี่เป็นคำถามของกรณีการใช้งานจริง ๆ ตัวอย่างเช่นหากคุณกำลังเขียน wrapper เพื่อดึงข้อมูลบางส่วนจาก API และเปิดเผยไปยังแอปพลิเคชันคุณสามารถตัดสินใจได้ว่าการร้องขอทรัพยากรที่ไม่มีอยู่จริงที่ส่งกลับ HTTP 404 นั้นสมเหตุสมผลกว่าที่จะจับได้และส่งคืน null ในทางกลับกันข้อผิดพลาด 406 (ไม่เป็นที่ยอมรับ) อาจคุ้มค่าที่จะโยนข้อผิดพลาดเนื่องจากนั่นหมายความว่ามีบางสิ่งเปลี่ยนไปและแอปควรหยุดทำงานและเบิร์นและกรีดร้องเพื่อขอความช่วยเหลือ

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