การใช้ข้อยกเว้นที่ไม่ได้จัดการแทนการใช้ 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# ของคุณมีประสิทธิภาพ ง่ายต่อการเข้าใจ และบำรุงรักษาได้