ให้เกิดความผิดพลาดน้อยที่สุด อย่างน้อยให้โปรแกรมทำงานต่อไปได้ 7. Exception ให้เกิดความผิดพลาดน้อยที่สุด อย่างน้อยให้โปรแกรมทำงานต่อไปได้ C# Programming with Visual C# 2010 Express
เป้าหมายการเรียนรู้ เอ็กเซ็บชันคืออะไร เอ็กเซ็บชันในดอตเน็ต การจัดการกับเอ็กเซ็บชัน และบล็อก try … catch บล็อก จัดการเอ็กเซ็บชัน ซ้อนกัน พร็อบเพอร์ตี้ของเอ็กเซ็บชันทั่วไป บล็อก finally คำสั่ง checked/ unchecked กับเอ็กเซ็บชัน การสร้างอ๊อปเจ็คเอ็กเซ็บชัน การโยนความผิดไปยังเมทธอดที่เรียกใช้งาน C# Programming with Visual C# 2010 Express
ความหมายของเอ็กเซ็บชัน และเหตุผล เอ็กเซ็บชัน มาจากศัพท์ว่า Exception แปลตามตัวว่า ได้รับการยกเว้น ไม่เป็นไปตามกฏ ในทางคอมพิวเตอร์ก็ ใช้ในทางความหมายใกล้เคียงนี้ แต่เฉพาะที่ตรงความ ผิดพลาดของโปรแกรม เพราะเกิดอะไรก็ตามที่ไม่เป็นไป ตามเงื่อนไข หรือการไม่ทำงานตามที่คาดหวังไว้ ให้ ยกเว้นไว้ ความผิดพลาดมีมากมาย นักเขียนโปรแกรมในรุ่นแรก ใช้ตรวจจับความผิดพลาด ด้วยการเขียนโปรแกรมใน เงื่อนไข เช่น if หรือ switch ให้ทำงานในเงื่อนไข ต่างๆ แต่ในกรณีที่นอกเหนือความคาดหวังในการทำงาน ผิดพลาดมากๆ โปรแกรมก็จะหยุดทำงาน เพราะไม่ สามารถทำงานในเงื่อนไขที่ตรวจสอบได้ จึงต้องมี Exception ให้ยกเว้นไว้ C# Programming with Visual C# 2010 Express
เอ็กเซ็บชันในเมทธอด ถ้า Method A( ) เรียกใช้ B( ) และ B( ) เรียกใช้ C( ) ถ้าเกิดความผิดพลาดในเมธอด C( ) เมธอด B( ) จะ ทำงานไม่ได้ และ A( ) ก็ทำงานไม่ได้ ถ้าเกิดความผิดพลาดในเมธอด B( ) เมธอด A( ) จะ ทำงานไม่ได้ A( ) เป็นเมธอดสุดท้าย ที่ควรจะต้องทำงานได้เสมอ เปรียบเสมือน ในโปรแกรมหลักต้องทำงานได้เสมอ การเขียน เอ็กเซ็บชัน ในเมธอดสุดท้ายจึงต้องมีเสมอ เพื่อโปรแกรมทำงานต่ไปได้ เมธอดสุดท้าย ใน C# คือ เมธอด main ( ) C# Programming with Visual C# 2010 Express
เอ็กเซ็บชันในดอนเน็ต คลาส Exception นี้ได้แยกประเภท เอ็กเซ็บชันได้เป็น คลาส สองประเภท คือ SystemException เป็นคลาสที่นิยามความผิดพลาดของระบบ ความผิดพลาดที่เกิดขึ้นจะส่งโดย CLR ยกตัวอย่างเช่น StackOverflowException เป็นเหตุการณ์ที่ CLR ตรวจสอบ พบว่าสเตกล้น ApplicationException เป็นเอ็กเซ็บชันที่นักพัฒนาแอปพลิเคชัน พัฒนาขึ้นใช้เอง(third parties) ถ้าต้องการที่สร้างเอ็กเซ็บชันให้ ครอบคลุมเงื่อนไขเฉพาะของตนเอง ควรใช้สืบทอดจากคลาสนี้ ได้ทั้งทางตรงและทางอ้อม C# Programming with Visual C# 2010 Express
แผนภาพคลาส บางส่วนของ Exception C# Programming with Visual C# 2010 Express
สำหรับเอ็บเซ็บชันที่ควรนำไปใช้บ่อยที่ควรรู้จัก ArgumentException เกิดขึ้นเมื่อผู้เรียกเมธอดโดยตัวแปรเข้า ไม่ตรงกับ ที่ต้องการของเมธอดนั้น เช่น มีตัวแปรเข้าไม่ ครบ หรือมีชนิดตัวแปรไม่ตรงกับที่ต้องการ FormatException เกิดขึ้นเมื่อรูปแบบตัวแปรเข้าไม่ตรงกับ ความต้องการ เช่น เมื่อเรียกเมธอดโดยใช้ตัวเข้าเป็นอักษร ที่ไม่ใช่รูปแบบของวันที่ (1-2-2010) StackOverflowException เกิดขึ้นเมื่อหน่วยความจำเต็มในส แตก อย่างเช่นการเรียกฟังก์ชันรีเคอซีพ หรือเมธอดเรียก ตัวเอง และมักเป็นความผิดพลาดที่ทำให้โปรแกรมหยุด ทำงาน EndOfStreamException เกิดขึ้นเมื่อพยายามที่จะเรียกอ่าน ไฟล์ทั้งๆที่ อ่านไฟล์ไม่ได้แล้วเนื่องจากจบไฟล์แล้ว OverflowException เกิดขึ้นเมื่อพยายามใช้คำสั่ง แปลง ค่า (cast) ตัวเลข แล้วเลยค่าสุดท้าย C# Programming with Visual C# 2010 Express
การใช้ Try... Catch ในการเขียนโปรแกรมเชิงวัตถุได้ใช้โครงสร้างการ แก้ปัญหาการจัดการกับความผิดพลาดในรูปของบล็อก try… catch… แทนการจัดการความผิดพลาดแบบเดิม โดยแยกการทำงานของโปรแกรมตามปกติ ไว้ในบล็อก try และส่วนที่ดูแลความผิดพลาดอยู่ในบล็อก catch โดยที่ เมื่อเกิดความผิดพลาดในบล็อก try จะโยน (throw) ความผิดนั้นไปในบล็อก catch ไวยกรณ์ของบล็อก เป็น ดังนี้ try { //… } catch ( class-type ) //…. C# Programming with Visual C# 2010 Express
ตัวอย่างการจัดการความผิดพลาด try { int x = 3; int y = 0; float ans; ans = x / y; } catch (Exception e) Console.WriteLine(e.Message); C# Programming with Visual C# 2010 Express
ลำดับชั้นของบล็อก catch ถ้าเกิดมีความผิด คนเมา ตกตึก ตาย อะไรคือสาเหตุ ที่ทำให้เขาตาย ตกตึก หรือเมา แน่นอน เขาตายเพราะตกตึก และเขาตกตึก เพราะเมา มันมีลำดับ ความผิดพลาดเช่น เดียวกับ คนเมา ตกตึก และตาย ถ้าเขาไม่เมา เขา อาจไม่ ตกตึก (แปลว่า บางที่เมาไม่ต้องตายก็ได้ ) การจัดการกับความผิดพลาด อาจป้องกัน ในหลายระดับ ทั้งระดับ ตกตึก และระดับเมา แต่อันใด จะป้องกันก่อน กัน โดยทั่วไป การจัดการความผิดพลาด เริ่มจากความ ผิดพลาดที่เฉพาะไปสู่ความผิดพลาดทั่วไป (ทำไมเป็น แบบนี้ ) C# Programming with Visual C# 2010 Express
ลำดับของเอ็กเซ็บชัน การใช้การจับความผิดพลาดของเอ็กเซ็บชันจะต้องเรียง จากลำดับแคบน้อยไปมาก เป็นกฏ หากไม่เป็นตามกฏจะไม่สามารถคอมไฟล์ได้ C# Programming with Visual C# 2010 Express
การจัดการลำดับการความผิดพลาดที่ผิดลำดับ try { int x = 3; int y = 0; float ans; ans = x / y; } catch (Exception e) //*****Error***** { Console.WriteLine(e.Message); catch (OverflowException over){ Console.WriteLine(over.Message); C# Programming with Visual C# 2010 Express
การใช้ try ซ้อน try การทำบล็อก try ซ้อนกัน หรือทำเน็สติ้ง (nesting) ของ บล็อก try ก็เหมือนกับการเขียนสเตทเม้นท์ทั่วไปของ C# การทำเน็ตติ้งนี้มีจะช่วยการจัดการความผิดพลาดใน ระดับโลคอล (local) ที่ต้องการแยกย่อยจัดการความ ผิดพลาด ได้ความเอ็กเซ็บชันที่ไม่สามารถใช้ลำดับชั้น ของเอ็กเซ็บชันได้ ตัวอย่าง เช่น จะมีการทดสอบความผิดพลาดของเอ็กเซ็บ ชันของไฟล์ด้วย FileNotFoundException ก่อน หากไม่มี ความผิดพลาดใดๆ ของการทำงานกับไฟล์ ก็จะเป็น ทดสอบเอ็กเซ็บชันของ ลำดับเอ็กเซ็บชันบล็อกนอกต่อไป C# Programming with Visual C# 2010 Express
พร็อบเพอร์ตี้ของเอ็กเซ็บชัน คำอธิบาย Message เป็นคำอธิบายความผิดพลาดที่เกิดขึ้น Source เป็นชื่ออ๊อปเจ็คหรือแอปพลิเคชัน ที่ทำให้เกิดความผิดพลาด StackTrace เป็นชุดข้อความในจุดที่ทำให้เกิดความผิดพลาด TargetSite เป็นชื่อของเมธอดที่ทำให้เกิดเอ็กเซ็บชัน InnerException ใช้สำหรับเก็บเอ็กเซ็บชันย่อย เช่น เมื่อเกิดเอ็กเซ็บชันของ X โดยที่ X ยังมีค่าการเกิดเอ็กเซ็บชัน Y HelpLine เป็นการกำหนด หรือเรียกไฟล์ช่วยเหลือที่สัมพันธ์กับเอ็กเซ็บชัน ให้อ่านเพิ่มเติม Data เป็นเรียกข้อมูลเพิ่มเติมเกี่ยวกับเอ็เซ็บชัน ที่ถูกกำหนดขึ้นเองในรูปของค่าเป็นคู่ Key/Value C# Programming with Visual C# 2010 Express
การใช้บล็อก finally กับเอ็กเซ็บชัน บล็อกไฟนอลลี่ เป็นการรับประกันการทำงานเสมอ แม้จะ มีเอ็กเซ็บชันหรือไม่ก็ตาม ไฟนอลลี่บล็อก มักใช้กับการคืนทรัพยากรที่ระบบได้ใช้ เสร็จแล้ว แม้มีความผิดพลาด หรือไม่มีความผิดพลาด จะคืนค่าทรัพยากรณีให้มีค่าดังเดิม หรือ ที่เรียกส่วนนี้ว่า Unmanaged ที่นอกเหนือ ที่ C# จะทำงานได้ เช่น ส่วน ระบบอื่นๆ ไม่ว่าจะเป็น ระบบฐานข้อมูล ระบบปฏิบัติการ ระบบเครื่อข่าย ตัวอย่างเช่น การเปิดการต่อเชื่อมกับระบบฐานข้อมูล เมื่อ ใช้งานเสร็จ ไม่ว่าจะทำงานกับฐานข้อมูลได้ผล หรือไม่ ได้ผลก็ตาม C# Programming with Visual C# 2010 Express
โครงสร้างของ try… catch ... finally... { // Statement in Try block. } catch ([catch specification]) // Statement in Catch block. finally // Statement in Finally block. C# Programming with Visual C# 2010 Express
ลำดับการทำงานของบล็อก try catch finally … ไม่มีความผิดพลาดใดๆ ทำงานต่อที่บล็อก finally เป็นลำดับสุดท้าย (ข้ามบล็อก catch ไป) มีความผิดพลาด จับความผิดพลาดได้ ทำงานที่บล็อก catch ทำงานต่อไปที่ บล็อก finally จับความผิดพลาดไม่ได้ ขึ้นอยู่กับเมธอดที่เรียกใช้งาน หาก เมธอดที่เรียกทำงานมีไม่มีเอ็กเซ็บชันรองรับโปรแกรมจะหยุด ทำงาน และบล็อก finally จะไม่ทำงาน ดังนั้นแล้วควรที่จะ ให้เอ็กเซ็บชันทั่วไป เป็นลำดับสุดท้าย ของบล็อก catch เพื่อให้จับความผิดพลาดได้ และให้บล็อก finally ทำงานได้ C# Programming with Visual C# 2010 Express
ตัวอย่างต่อไปนี้เป็นการใช้ try … catch… finally String cnString = "xyz"; System.Data.SqlClient.SqlConnection cn = new System.Data.SqlClient.SqlConnection(); try { cn.ConnectionString = cnString; //error cn.Open(); } catch (Exception e) { Console.WriteLine(e.Message); finally { cn.Close(); cn.Dispose(); C# Programming with Visual C# 2010 Express
การใช้คีย์เวิร์ด Checked, Unchecked หรือกำหนดใน Project Property ใน Build Tab คลิก เลือกปุ่มคำสั่ง Advanced อยู่ด้านขวาล่าง จะเกิด หน้าต่าง Advanced Build Setting แล้วคลิกเลือก Check for arithmetic overflow/underflow C# Programming with Visual C# 2010 Express
ตัวอย่าการใช้ checked static void Main(string[] args){ try { Console.WriteLine(Multiply(2, 32767)); } catch (OverflowException e) { Console.WriteLine(e.Message); catch (Exception e) { } static short Multiply(short x, short y){ return checked((short)(x * y)); C# Programming with Visual C# 2010 Express
การสร้างอ๊อปเจ็คเอ็กเซ็บชัน การสร้างอ๊อปเจ็คเอ็กเซ็บชันใหม่ เพื่อปรับแต่งการอธิบาย ความผิดพลาดให้ตรงกับที่ต้องการจริงๆ มากกว่าที่จะใช้ ค่าปริยายของเอ็กเซ็บชันของคลาสเดิม การปรับแต่งให้ตรงกับความต้องการมักใช้ การเปลี่ยนการ อธิบายความผิดพลาด เช่น ในที่นี้จะใช้คำอธิบายเป็น ภาษาไทย เพื่ออธิบายความผิดพลาดจากเดิมใช้ค่าปริยาย ในรูปแบบภาษาอังกฤษ หรือเปลี่ยนคำอธิบายให้ตรงกับ ความผิดพลาดที่จะเกิดขึ้น // ตัวอย่างที่ 1 // สร้างอ๊อปเจ็ค FormatException ที่มีข้อความอธิบายความผิดพลาด FormatException ex = new FormatException("รูปแบบตัวแปรเข้าไม่ถูกต้อง"); ... C# Programming with Visual C# 2010 Express
คำสั่ง throw เมื่อมีความผิดพลาดที่ตน แต่ไม่อยากรับผิดชอบ มีวิธีที่ ดีกว่าที่จะทำให้ตนเองไม่ต้องเสียหาย โดยโยนความผิดให้ คนอื่นรับผิดชอบแทนไป ใน c# ใช้คีย์เวิร์ด throw โยนไปเลย ไปยังเมธอดอื่น ถ้าเมธอดที่รับความผิดพลาด ไม่มีการการจัดการความ ผิดพลาดละ จะเกิดอะไรขึ้น คำตอบ ก็เป็นเรื่องของ(เมธ อด)คุณ แต่โดยธรรมชาติ แล้วโปรแกรมเมอร์ จะไม่ทำอย่างนั้น อย่างนั้นก็ต้องให้เมธอดที่รับไป ต้องมีการจัดการกับความ ผิดพลาดนั้นบ้าง (พอรับมือได้) โดยทั้วไป เมธอดที่รับความผิดจากโยน จะเป็นเมธอดที่ เรียกใช้งานคนอื่น (เมธอดอื่น) จึงเป็นธรรมดาที่ต้องรู้ วิธีการจัดการผิดพลาด ที่จะมีผลตามมา C# Programming with Visual C# 2010 Express
การโยนความผิดให้กับเมธอดทีเรียก try { //สเตทเม้นท์ที่อาจเกิดความผิดพลาดขึ้นได้ } catch (FormatException ex) //พยายามจะจัดการกับความผิดพลาดแต่ทำไม่ได้ //จึงโยนความผิดให้เมธอดที่เรียกจัดการแทน throw; C# Programming with Visual C# 2010 Express
ตัวอย่าง การใช้ throw ตัวอย่างต่อไปนี้เป็นตัวอย่าง WPF แอปพลิเคชัน ที่รับค่าตัวเลขเพื่อใช้ในการคูณ ผ่าน textbox สองกล่อง และเมื่อคลิกปุ่มคำสั่งให้ทำงาน จะนำผลที่คูณได้ไปแสดงที่ label C# Programming with Visual C# 2010 Express
ตัวอย่าง การใช้ throw ตัวอย่างโปรแกรมนี้ มีเมธอด Multiply( ) ที่ส่งค่าคืนในรูป short ซึ่งภายในเมธอดนี้จะมีการโยนความผิดพลาดเมื่อผลคูณเกิน ค่าที่เก็บได้ของ short ในเมธอด Main( ) เรียกใช้งานเมธอด Multiply( ) โดยการรับค่า ข้อมูลจากกล่องข้อมูล สองกล่องข้อมูล เพื่อนำไป ประมวลผลตามเมธอด Multiply( ) ความผิดพลาดอาจเกิดขึ้น ได้คือ ความผิดพลาดที่เกิดจากไม่ใส่ข้อมูลอะไร ความผิดพลาดที่เกิดจาก ใส่ข้อมูลเกินขนาด ชนิดข้อมูล short (ไม่ได้มาจากผลคูณ) ความผิดพลาดที่เกิดจากการโยนความผิดพลาดของเมธอด Multiply( ) เมื่อผลการคูณเกิดค่าที่เก็บได้ C# Programming with Visual C# 2010 Express
ตัวอย่าง การใช้ throw try { short x, y; x = short.Parse(this.textBox1.Text); y = short.Parse(this.textBox2.Text); this.label1.Content = this.Multiply(x,y); } catch (FormatException) { MessageBox.Show("ใส่ตัวคูณไม่อยู่ในรูปตัวเลข" ); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private short Multiply(short x, short y) { try { return checked((short)(x * y)); } catch (Exception) { throw new OverflowException("ผลการคูณเกินค่า short"); C# Programming with Visual C# 2010 Express
แนวทางการจัดการเอ็กเซ็บชัน สำหรับวิธีที่เหมาะสมและควรสำหรับการจัดการกับเอ็กเซ็บ ด้วยการใช้กลุ่มคำสั่ง try{…} catch{…} หรือการสร้างอ๊อป เจ็คแล้วทำงานโยนด้วยคำสั่ง throw แยกได้สองแนวทาง คือ การใช้ catch และ throw ถ้าต้องการทำเป็นลำดับชัน ควรใช้ catch และความ ผิดพลาดที่มีนิยามในดอทเน็ตแล้ว การโยนความผิดด้วยคำสั่ง throw ซึ่งได้มาจากการสร้างอ๊ อปเจ็คเอ็กเซ็บชัน ที่ไม่ควรเป็นเอ็กเซ็บชันทั่วไป เช่น คลาส Exception เพราะสามารถจัดการได้เมธอดที่เรียกใช้ งานอยู่แล้ว ควรเป็นความผิดพลาดที่เฉพาะที่เกิดขึ้นได้กับ เมธอดที่ถูกเรียกใช้งาน C# Programming with Visual C# 2010 Express
คำถามทบทวน เอ็กเซ็บชันมีไว้เพื่อทำอะไร การเขียนเอ็กเซ็บชันไม่อยู่ในเมธอดได้หรือไม่ คลาสอะไรเป็นคลาสหลักของเอ็กเซ็บชัน ความผิดพลาดเกี่ยวกับตัวเลขมีขนาดเกิดชนิดข้อมูลที่จะ เก็บได้ จะจัดการกับความผิดพลาดนี้อย่างไร ในกรณีที่จะจัดการกับชุดชนิดของเอ็กเซ็บชัน จะจัดการ ด้วยใช้คำสั่ง try… catch อย่างไร อธิบายลำดับการงานของบล็อก try { …} catch { …} finally{… } เมื่อมีการทำงานของเอ็กเซ็บชันโดยการใช้คำสั่ง throw ต่อมาจะทำงานในที่ใดต่อไป C# Programming with Visual C# 2010 Express