การใช้ข้อยกเว้นที่ไม่ได้จัดการแทนการใช้ Contains() ในคอลเลกชัน C#
เมื่อทำงานกับคอลเลกชันใน C# นักพัฒนาส่วนใหญ่จำเป็นต้องตรวจสอบว่าวัตถุเฉพาะใดๆ นั้นมีอยู่หรือไม่ อย่างไรก็ตาม มักจะมีกรณีที่คอลเลกชันที่ใช้ไม่มีวิธี Contains()
ในตัว ซึ่งทำให้เกิดคำถามเกี่ยวกับวิธีการแก้ไขปัญหานี้ แนวทางที่นักพัฒนาบางคนใช้บ่อยแต่ไม่แนะนำคือการใช้ข้อยกเว้นที่ไม่ได้จัดการแทนการตรวจสอบการมีอยู่ของวัตถุอย่างชัดเจน บทความนี้จะเปิดเผยว่าทำไมแนวทางนี้จึงไม่แนะนำและสำรวจทางเลือกที่ดีกว่า
ความเข้าใจในปัญหา
จินตนาการว่าคุณกำลังทำงานกับคอลเลกชันของการควบคุมในแอปพลิเคชัน Windows Forms คุณต้องการตรวจสอบการมีอยู่ของการควบคุมเฉพาะ แต่คอลเลกชันนั้นไม่มีวิธี Contains()
อาจมีวิธีการสองแบบดังนี้:
- สร้างวิธีการ
Contains()
ของคุณเอง ซึ่งต้องทำการวนลูปผ่านคอลเลกชันเพื่อตรวจหาวัตถุที่ระบุ ซึ่งโดยทั่วไปถือเป็นแนวปฏิบัติที่ดีที่สุด - ใช้บล็อก
try-catch
เพื่อพยายามเข้าถึงวัตถุโดยตรง ซึ่งหากมีข้อยกเว้นถูกโยนออกมาจะหมายถึงว่าวัตถุนั้นไม่มีอยู่
try
{
Object aObject = myCollection[myObject];
}
catch(Exception e)
{
// จัดการข้อยกเว้นหากวัตถุไม่มีอยู่
}
แม้ว่าจะดูเหมือนว่าสะดวกในการจับข้อยกเว้นเมื่อไม่พบวัตถุ แต่เราก็ควรตั้งคำถามเกี่ยวกับคุณภาพของแนวทางนี้
ทำไมการใช้ข้อยกเว้นสำหรับการควบคุมการไหลจึงเป็นแนวทางที่ไม่ดี
1. ค่าใช้จ่ายด้านประสิทธิภาพของข้อยกเว้น
การโยนและจับข้อยกเว้นไม่ใช่เพียงกลไกสำหรับการรายงานข้อผิดพลาด; มันนำมาซึ่งค่าใช้จ่ายด้านประสิทธิภาพ เมื่อใช้ข้อยกเว้นเพื่อควบคุมการไหลแทนที่จะเป็นการตรวจสอบแบบวนลูป:
- การวนลูป ผ่านคอลเลกชันนั้นตรงไปตรงมาซึ่งมีค่าใช้จ่ายที่ทราบ
- การจับข้อยกเว้น อย่างไรก็ตาม เกี่ยวข้องกับค่าใช้จ่ายที่สำคัญ การจัดการข้อยกเว้นจะเปลี่ยนแปลงการไหลของโปรแกรม และการใช้มากเกินไปทำให้ประสิทธิภาพช้าและแอปพลิเคชันไม่ตอบสนอง
2. การจัดการข้อผิดพลาดที่ไม่ชัดเจน
หนึ่งในปัญหาหลักของการใช้ข้อยกเว้นเพื่อตรวจสอบการมีอยู่คือ การสูญเสียความเฉพาะเจาะจง เมื่อตรวจจับข้อยกเว้นมันไม่แสดงปัญหาที่แน่ชัด สาเหตุหลายประการอาจทำให้เกิดข้อยกเว้น:
- วัตถุเฉพาะอาจไม่มีในคอลเลกชัน
- คอลเลกชันอาจเป็น null เมื่อต้องเข้าถึง
- ปัญหาอาจเกิดจากการแปลงประเภท
ทั้งหมดนี้ส่งผลให้เกิดการจัดการข้อยกเว้นทั่วไปเดียว ซึ่งไม่เป็นประโยชน์สำหรับการวิเคราะห์หรือการควบคุมการไหลที่ตั้งใจไว้
3. ความสามารถในการบำรุงรักษาโค้ด
โค้ดที่ใช้การจัดการข้อยกเว้นสำหรับการควบคุมการไหลปกตินั้นอาจเป็นเรื่องยากในการบำรุงรักษาและทำความเข้าใจ นักพัฒนาที่สืบทอดโค้ดนี้จะมีความยุ่งยากในการตีความเจตนา ส่งผลให้เกิดข้อผิดพลาดและการจัดการข้อผิดพลาดที่ไม่มีประสิทธิภาพ
ทางเลือกที่ดีกว่า
เพื่อหลีกเลี่ยงกับดักของการใช้ข้อยกเว้นอย่างไม่เหมาะสม ให้พิจารณาวิธีการดังต่อไปนี้:
- สร้างวิธีการ Contains ที่กำหนดเอง: นี่เป็นโซลูชันที่สะอาดและมีประสิทธิภาพที่สุด และทำให้การดำเนินการทั้งหมดมีความคาดหมาย แค่ทำการวนลูปผ่านคอลเลกชันก็เพียงพอแล้ว
public bool Contains(Object myObject)
{
foreach (var obj in myCollection)
{
if (obj.Equals(myObject))
{
return true;
}
}
return false;
}
- ใช้พจนานุกรมหรือ Hashtables: หากคุณต้องการตรวจสอบการมีอยู่ของวัตถุอย่างบ่อยครั้ง การใช้
Dictionary
หรือHashtable
จะเป็นทางเลือกที่เหมาะสมกว่า คอลเลกชันเหล่านี้ได้รับการปรับให้เหมาะสมสำหรับการค้นหาคีย์และรวมถึงวิธีContainsKey
ทำให้การตรวจสอบการมีอยู่เป็นเรื่องง่ายและมีประสิทธิภาพ
if (myDictionary.ContainsKey(myObjectKey))
{
// วัตถุมีอยู่
}
สรุป
ในขณะที่การใช้ข้อยกเว้นที่ไม่ได้จัดการสำหรับการตรวจสอบการมีอยู่ของวัตถุในคอลเลกชันอาจดูเหมือนการแก้ปัญหาอย่างรวดเร็ว แต่มันคือแนวทางการเขียนโปรแกรมที่ไม่มีประสิทธิภาพและไม่ดี วิธีการ Contains()
ที่กำหนดเองหรือคอลเลกชันที่เหมาะสมไม่เพียงแต่ส่งเสริมประสิทธิภาพที่ดียิ่งขึ้นเท่านั้น แต่ยังเพิ่มความชัดเจน ความสามารถในการบำรุงรักษา และความเชื่อถือได้ของโค้ดของคุณ
สำหรับการอ่านเพิ่มเติมเกี่ยวกับข้อยกเว้นและการใช้งานอย่างเหมาะสม ตรวจสอบบทความเหล่านี้:
การใช้แนวทางที่เป็นระบบในการจัดการคอลเลกชันจะช่วยให้แอปพลิเคชัน C# ของคุณมีประสิทธิภาพ ง่ายต่อการเข้าใจ และบำรุงรักษาได้