Exception

11 February 2016

ในบทนี้ คุณจะได้เรียนและทำความรู้จักกับ Exception ในภาษา C# รวมถึงการใช้งาน Exception จากไลบรารี่ที่ภาษา C# มีให้ และการจัดการและสร้าง Exception แบบกำหนดเอง

Exception คืออะไร

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

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

try {
    // Statement to execute
}
catch (ExceptionType1 ex1) {
    // Handing exception 1
}
catch (ExceptionType2 ex2) {
    // Handing exception 2
}
...
catch (ExceptionTypen exn) {
    // Handing exception n
}

โดยในบล็อคคำสั่ง try เป็นส่วนของการทำงานที่ของโปรแกรม และบล็อคคำสัง catch เป็นการจัดการกับ exception แต่ละแบบที่เกิดขึ้น โดย Exception นั้นสามารถเกิดขึ้นได้เพียงหนึ่งอย่างเท่านั้นในขณะหนึ่งเวลาของโปรแกรม

การใช้งาน Exception

ต่อไปเป็นตัวอย่างการจัดการ Exception ที่เกิดขึ้น โดยตัวอย่างนี้จะเป็นการใช้ Exception ออบเจ็ค DivideByZeroException จาก namespace system ของภาษา C# โดยเป็นโปรแกรมหารตัวเลขอย่างง่าย โดยโปรแกรมจะรับตัวเลขสองตัวมาจากผู้ใช้และทำการหาร

using System;

namespace Exception1
{
    class Program
    {
        static void Main(string[] args)
        {
            int a;
            int b;

            Console.WriteLine("Divider Program");

            Console.Write("Enter number a: ");
            a = Int16.Parse(Console.ReadLine());
            Console.Write("Enter number b: ");
            b = Int16.Parse(Console.ReadLine());

            try {
                Console.WriteLine("The result of a / b is " + (a / b));
            } catch (DivideByZeroException ex) {
                Console.WriteLine("Exception Divide by Zero occur:" + ex);
            }
        }
    }
}

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

คำสั่ง try catch

การใช้ Exception นั้นจะเริ่มต้นด้วยคำสั่ง try โดยในบล็อคของคำสั่งนี้จะเป็นส่วนที่คาดว่า Exception จะเกิดขึ้น โดยในตัวอย่างก็คือการหารตัวเลขด้วย 0 นั่นหมายความว่ามันมีโอกาสที่ผู้ใช้จะกรอกค่า b เป็น 0 ได้

try {
    Console.WriteLine("The result of a / b is " + (a / b));
}

และต่อมาในบล็อคของคำสั่ง catch เป็นส่วนในการจัดการเมื่อเกิด Exception ขึ้น นั่นคือเมื่อผู้ใช้ใส่ตัวเลขสำหรับ b เป็น 0 โปรแกรมจะทำการ throw exception มายังบล็อคนี้

catch (DivideByZeroException ex) {
    Console.WriteLine("Exception Divide by Zero occur:" + ex);
}

และข้างล่างเป็นตัวอย่างของโปรแกรม เมื่อผู้ใช้กรอกตัวเลขที่สามารถหารกันได้ นั่นคือตัวหารไม่เป็น 0

Divider Program
Enter number a: 15
Enter number b: 3
The result of a / b is 5

และข้างล่างเป็นตัวอย่างเมื่อผู้ใช้กรอกตัวหารเป็น 0 โปรแกรมจะ throw exception ไปยังบล็อคของคำสั่ง catch และแสดงผลของ exception ในออบเจ็ค ex ออกมา ซึ่งเกิดจากการ Override ในเมธอด ToString() ของออบเจ็ค

Divider Program
Enter number a: 10
Enter number b: 0
Exception Divide by Zero occur: System.DivideByZeroException: Attempted to divide by zero...

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

using System;

namespace Exception1
{
    class Program
    {
        static void Main(string[] args)
        {
            int a;
            int b;

            bool succeed;

            Console.WriteLine("Divider Program");

            try {
                Console.Write("Enter number a: ");
                a = Int16.Parse(Console.ReadLine());
                Console.Write("Enter number b: ");
                b = Int16.Parse(Console.ReadLine());

                try
                {
                    Console.WriteLine("The result of a / b is " + (a / b));
                }
                catch (DivideByZeroException ex)
                {
                    Console.WriteLine("Exception Divide by Zero occur: " + ex);
                }

            } catch (FormatException ex) {
                Console.WriteLine("You must enter numbers.");
            } finally {
                Console.WriteLine("The program always enter finally block.");
            }

        }
    }
}

ในตอนนี้เราได้พัฒนาโปรแกรมของเราให้จัดการกับข้อมูลที่ไม่ถูกต้องได้แล้ว นั่นคือเมื่อผู้ใช้ใส่อย่างอื่นที่ไม่ใช่ตัวเลข เพราะการใช้เมธอด Int16.Parse() เป็นเมธอดในการแปลง string ไปเป็น Integer นั้นจะทำให้เกิด Exception ขึ้นในกรณีที่ข้อมูลที่นำมาแปลงไม่ใช่ตัวเลข คุณเห็นบางอย่างซับซ้อนขึ้น นั่นคือเราได้ทำการซ้อน Exception เพราะว่าแน่นอน มันสามารถซ้อนกันได้เหมือนกับคำสั่ง If อยู่แล้ว และคุณเห็นคำสั่งใหม่เพิ่มเข้ามาคือ finally

คำสั่ง Finally

ในบล็อคของคำสั่ง Finally นั้นจะเป็นบล็อคที่โปรแกรมจะเข้ามาทำงานเสมอ หลังจากที่มันทำงานในบล็อคของ try เสร็จ หรืออาจจะเป็นในบล็อคของ catch ก็ตาม มันมักจะใช้กับการทำงานที่มีโอกาสเกิดข้อผิดพลาดขึ้นในคำสั่ง try แต่ไม่มีการ Throw Exception เช่นการทำงานกับไฟล์ การเปิดไฟล์นั้นไม่ว่าจะเปิดสำเร็จหรือไม่ ก็ไม่เกิด Exception ดังนั้นคำสั่ง Finally ใช้สำหรับจัดการเมื่อการทำงานเสร็จสิ้นหรือไม่เป็น สำหรับตัวอย่าง

System.IO.FileStream file = null;
System.IO.FileInfo fileinfo = new System.IO.FileInfo("D:\\marcus.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(1);
}
finally
{
    // Check if file is successfully opened
    if (file != null)
    {
        file.Close();
    }
}

Throwing Exceptions

เมื่อเกิด Exception ขึ้นโปรแกรม จะ Throw exception ไปยัง catch block และในภาษา C# นั้นคุณสามารถใช้คำสั่ง throw เพื่อ throw exception ไปยัง Exception Handle ที่คุณต้องการได้

using System;

namespace Exception1
{
    class Program
    {
        static void Main(string[] args)
        {
            int index = -1;
            string[] array = new string[] { "One", "Two", "Three" };

            try
            {
                if (index > array.Length - 1)
                    throw new IndexOutOfRangeException();
                else if (index < 0)
                    throw new ArgumentException();
                Console.WriteLine("Your number is " + array[index]);
            }
            catch (IndexOutOfRangeException ex)
            {
                Console.WriteLine("IndexOutOfRangeException is thrown.");
            }
            catch (ArgumentException ex)
            {
                Console.WriteLine("ArgumentException is thrown.");
            }
        }
    }
}

จากตัวอย่างด้านบน เป็นการใช้คำสั่ง throw ในการ throw exception ไปยัง catch block ที่ต้องการ โดยปกตินั้นถ้าหาก index ของอาเรย์ไม่ถูกต้องโปรแกรมจะทำการ throw ไปยัง IndexOutOfRangeException อยู่แล้ว แต่ในตอนนี้เราได้ให้โปรแกรม throw ไปยัง ArgumentException ได้ถ้าหาก index เป็นค่าลบ

Creating Exceptions

บางครั้งคุณอาจจะต้องการสร้าง Exception ของคุณเพื่อจัดการกับบางอย่างที่ในภาษา C# ไม่มีให้ คุณสามารถทำได้ โดยสร้าง Exception ของคุณขึ้นมาเพื่อจัดการกับปัญหา โดยการสร้างคลาสที่ inherit มาจากคลาส System.Exception

using System;
using System.Collections.Generic;

namespace Exception1
{
    class Program
    {
        static void Main(string[] args)
        {

            List<string> names = new List<string>();
            names.Add("Marcus");
            names.Add("James");
            names.Add("Daneil");

            string nameSearch = "Thomas";

            try {
                if (!names.Contains(nameSearch)) {
                    throw new NameNotFoundException(nameSearch);
                } else {
                    Console.WriteLine("Hello " + nameSearch + "!");
                }
            }
            catch (NameNotFoundException ex) {
                Console.WriteLine(ex);
            }
        }
    }

    public class NameNotFoundException : Exception
    {
        string name;

        public NameNotFoundException()
        {
        }

        public NameNotFoundException(string message)
            : base(message)
        {
            this.name = message;
        }

        public NameNotFoundException(string message, Exception inner)
            : base(message, inner)
        {
        }

        public override string ToString()
        {
            return "A person named \"" + this.name + "\" is not found.";
        }
    }
}

จากตัวอย่าง เป็นการสร้างคลาส exception ของคุณเอง เราเรียกว่า user-defined exception เป็น Exception ในการจัดการในกรณีที่ไม่มีชื่ออยู่ใน List เราใช้คำสั่ง if เพื่อตรวจสอบว่ามีคนที่ชือ Thomas ในลิสต์หรือไม่

if (!names.Contains(nameSearch)) {
     throw new NameNotFoundException(nameSearch);
}

ถ้ามีเราก็แสดงการทักทาย และถ้าไม่มีในตอนนี้เราจะทำการ Throw ไปยัง Exception ที่เราได้สร้างขึ้น ด้วยคำสั่ง throw new NameNotFoundException(nameSearch); และส่ง nameSeach เป็นพารามิเตอร์สำหรับ constructor ของคลาส ผลลัพธ์ก็คือโปรแกรมทำการ throw ไปยัง catch block ของ NameNotFoundException

User-Defined Exceptions

เราได้สร้างคลาส Exception ที่มีชื่อว่า NameNotFoundException โดย inherit จากคลาส Exception ที่อยู่ภายใน namespace system ของภาษา C# โดยมี constructor 3 แบบ โดย constructor เราใช้ในตัวอย่างคือ

public NameNotFoundException(string message)

โดยเก็บค่าของชื่อเก็บไว้ในตัวแปร name ของคลาส เพราะว่าใน catch block โปรแกรมหลักนั้น เราได้ใช้คำสั่ง Console.WriteLine(ex); ซึ่งเป็นการเรียกใช้ตัวแปรออบเจ็ค (object instance) โดยผลลัพธ์ที่ได้จากตัวแปรนั้นจะเป็นค่าที่ได้มากจากเมธอด ToString() ต่อไปเราได้ทำการ override เมธอด ToString() เพื่อให้มันแสดงข้อความตามที่ต้องการ (ถ้าคุณไม่ override มันจะแสดงจาก base คลาสโดย default)

public override string ToString()
{
    return "A person named \"" + this.name + "\" is not found.";
}

และในผลลัพธ์โปรแกรมของเราจะแสดงข้อความ "A person named "Thomas" is not found." เพราะว่าเป็นผลจากเมธอด ToString()

ในบทนี้ คณได้เรียนรู้เกี่ยวกับการใช้งาน Exception ในภาษา C# นอกจากนี้คุณยังสามารถสร้าง Exception ของคุณได้เอง เพื่อจัดงานในงานที่คุณต้องการที่ในภาษา C# ไม่มีให้

บทความนี้เป็นประโยชน์หรือไม่? Yes · No