زنگ سی شارپ – قسمت چهل و هشتم

بررسی مبحث Exception Handling، توضیحاتی در مورد کلاس Exception و نحوه‌ی ساختن custom exception


۱۶ دیدگاه سی شارپ سه شنبه, ۱۰ام دی , ۱۳۹۲ 16439 بازدید

زنگ سی‌شارپ - قسمت چهل و هفتم

نگاهی دقیق‌تر به Exception Class

تا به این‌جا، ما exception ها را می‌گرفتیم اما هیچ‌کاری با شیء exception نمی‌کردیم. همان‌طور که پیش‌تر توضیح داده شد، قسمت catch به شما اجازه می‌دهد تا exception type و variable را مشخص کنید. Variable شامل یک reference متصل به exception object است. از آن‌جایی که تمامی exception ها از Exception Class ارث‌بری کرده‌اند، همه‌ی آن‌ها به اعضای Exception Class دسترسی دارند. در این‌جا با تعدادی از مفیدترین اعضای Exception Class آشنا خواهید شد.

Exception Class تعدادی property دارد که سه عدد از مهم‌ترین آن‌ها Message، StackTrace و TargetSite هستند. این property ها هرسه read-only هستند. Message شامل یک رشته است که ماهیت خطا را شرح می‌دهد. StackTrace شامل یک رشته است که این رشته شامل فراخوانی‌هایی است که منجر به خطا شده‌اند. TargetSite شامل یک شیء بوده که مشخص‌کننده متد تولیدکننده‌ی exception است.

Exception Class همچنین شامل چندین متد است.  یکی از آن متدها که قبلاً استفاده کرده‌اید، ()ToString است. این متد یک رشته را return می‌کند که خطا شرح می‌دهد. به‌عنوان مثال، هنگامی‌که یک exception توسط ()Console.WriteLine نمایش داده شود، متد ()ToString به‌طور خودکار فراخوانی خواهد شد.

برنامه‌ی زیر این property ها و متدها را نشان می‌دهد:

using System;
class ExcTest
{
    public static void GenException()
    {
        int[] nums = new int[4];

        Console.WriteLine("Before exception is generated.");

        // Generate an index out-of-bounds exception.
        for (int counter = 0; counter < 10; counter++)
        {
            nums[counter] = counter;
            Console.WriteLine("nums[{0}]: {1}", counter, nums[counter]);
        }

        Console.WriteLine("this won't be displayed");
    }
}
class Program
{
    static void Main(string[] args)
    {
        try
        {
            ExcTest.GenException();
        }
        catch (IndexOutOfRangeException exc)
        {
            Console.WriteLine("Standard message is: ");
            Console.WriteLine(exc); // calls ToString()
            Console.WriteLine("Stack trace: " + exc.StackTrace);
            Console.WriteLine("Message: " + exc.Message);
            Console.WriteLine("TargetSite: " + exc.TargetSite);
        }
        Console.WriteLine("After catch block.");
    }
}

/* Output
 
Before exception is generated.
nums[0]: 0
nums[1]: 1
nums[2]: 2
nums[3]: 3
Standard message is:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at ExcTest.GenException()
at UseExcept.Main()
Stack trace: at ExcTest.GenException()
at UseExcept.Main()
Message: Index was outside the bounds of the array.
TargetSite: Void GenException()
After catch block.
 
*/

خروجی برنامه‌ی بالا گویای مطلب فوق است.

System namespace شامل تعدادی exception توکار (built-in) و استاندارد است که همه‌ی آن‌ها (چه به‌صورت مستقیم و چه به‌صورت غیرمستقیم) از SystemException ارث‌بری کرده‌اند.

در زیر لیستی از پر استفاده‌ترین exception های استاندارد را می‌بینید:

/* More commonly used standard exceptions
 
Exception: ArrayTypeMismatchException
 * Meaning: Type of value being stored is incompatible 
   with the type of the array.

Exception: DivideByZeroException
 * Meaning: Division by zero attempted.

Exception: IndexOutOfRangeException
 * Meaning: Array index is out-of-bounds.

Exception: InvalidCastException
 * Meaning: A runtime cast is invalid.

Exception: OutOfMemoryException
 * Meaning: Insufficient free memory exists to continue program
            execution. For example, this exception will be thrown if
            there is not sufficient free memory to create an object
            via new.

Exception: OverflowException
 * Meaning: An arithmetic overflow occurred.

Exception: NullReferenceException
 * Meaning: An attempt was made to operate on a null reference—that
            is, a reference that does not refer to an object.
 
*/

Exception های بالا همه واضح هستند و نام آن‌ها بیان کننده‌ی معنای آن‌هاست. NullReferenceException هنگامی پرتاب می‌شود که قصد داشته باشید از یک reference استفاده کنید درحالی‌که null است. مثل هنگامی‌که بخواهید یک متد را از یک null reference فراخوانی کنید. Null reference عبارت است از reference ای که به هیچ شیء‌ای وصل نیست. یک راه برای ساختن null reference این است که یک reference را برابر با مقدار null (با استفاده از کلمه‌ی کلیدی null) قرار دهید.

به مثال زیر که NullReferenceException را شرح می‌دهد دقت کنید:

// Use the NullReferenceException.
using System;
class X
{
    int x;
    public X(int a)
    {
        x = a;
    }

    public int Add(X o)
    {
        return x + o.x;
    }
}
// Demonstrate NullReferenceException.
class NREDemo
{
    static void Main()
    {
        X p = new X(10);
        X q = null; // q is explicitly assigned null
        int val;

        try
        {
            val = p.Add(q); // this will lead to an exception
        }
        catch (NullReferenceException)
        {
            Console.WriteLine("NullReferenceException!");
            Console.WriteLine("fixing...\n");

            // Now, fix it.
            q = new X(9);
            val = p.Add(q);
        }

        Console.WriteLine("val is {0}", val);
    }
}

/* Output
 
NullReferenceException!
fixing...

val is 19
 
*/

برنامه‌ی بالا یک کلاس به اسم X دارد که شامل یک عضو به اسم x و یک متد ()Add است که یک شیء از جنس کلاس X می‌گیرد و آن را با متغیر x درون کلاس جمع می‌کند. در متد ()Main دو شیء از کلاس X ساخته شده که یکی از آن‌ها (p) مقداردهی شده و دیگری (q) برابر با null است. سپس ()p.Add با آرگومان q فراخوانی می‌شود. از آن‌جایی که q به هیچ شیء‌ای اشاره نمی‌کند، NullReferenceException تولید شده و در بلوک مربوطه handle می‌شود.

ارث‌بری از Exception Class

اگرچه exception های built-in سی‌شارپ اکثر خطاهای رایج را handle می‌کنند، اما مکانیزم exception-handling در سی‌شارپ به این خطاها محدود نیست. در واقع، بخشی از قدرت رویکرد سی‌شارپ به exception ها، توانایی handle کردن exception type هایی است که خودتان می‌سازید. شما می‌توانید exception های خودتان را برای handle کردن خطاهای به‌وجود آمده بسازید (custom exception). ساختن یک exception بسیار ساده است، تنها کافی است یک کلاس تعریف کنید و آن کلاس از Exception ارث‌بری کرده باشد. کلاس مشتق شده‌ی شما در واقع نیازی برای اجرای هیچ چیزی ندارد. هنگامی‌که کلاس‌های شما از Exception ارث‌بری می‌کنند، وجود آن‌ها در type system موجب می‌شود تا بتوانید از آن‌ها به‌عنوان exception استفاده کنید. در گذشته custom exception ها از ApplicationException ارث‌بری می‌کردند اما اکنون دیگر مایکروسافت این کار را پیشنهاد نمی‌کند بلکه پیشنهاد مایکروسافت ارث‌بری از Exception Class است.

exception هایی که شما می‌سازید شامل property و method هایی است که Exception class برای آن فراهم می‌سازد. همچنین می‌توانید تعدادی از اعضای آن را در exception class ای که خود ساخته‌اید، override کنید.

هنگامی‌که exception class خودتان را می‌سازید، معمولاً می‌خواهید که کلاس شما از تمامی constructor های موجود در کلاس Exception (والد) پشتیبانی کند. برای custom class exception های کوچک، این کار بسیار راحت است زیرا می‌توانید به‌سادگی، argument های مربوط به هر constructor مرتبط با کلاس Exception (والد) را از طریق کلمه‌ی کلیدی base ارسال کنید.

کلاس Exception شامل constructor های زیر است:

public Exception()
public Exception(string message)
public Exception(string message, Exception innerException)
protected Exception(System.Runtime.Serialization.SerializationInfo info,
                    System.Runtime.Serialization.StreamingContext context)

البته تنها نیاز به نوشتن آن constructor هایی دارید که قصد دارید در برنامه‌تان از آن‌ها استفاده کنید.

در مثال زیر، کلاس RangeArray از آرایه‌های یک بعدی از نوع int پشتیبانی می‌کند که index شروع و پایان آن‌ها توسط کاربر مشخص می‌شود. برای مثال، آرایه‌ای از بازه‌ی ۵- تا ۲۷ برای RangeArray کاملاً صحیح است.

در مثال زیر، به چگونه‌گی ساخت custom exception و نحوه‌ی استفاده از آن توجه کنید:

// Use a custom Exception for RangeArray errors.
using System;
// Create a RangeArray exception.
class RangeArrayException : Exception
{
    /* Implement all of the Exception constructors. Notice that
    the constructors simply execute the base class constructor.
    Because RangeArrayException adds nothing to Exception,
    there is no need for any further actions. */

    public RangeArrayException() : base() { }
    public RangeArrayException(string message) : base(message) { }
    public RangeArrayException(string message, Exception innerException) :
        base(message, innerException) { }
    protected RangeArrayException(
    System.Runtime.Serialization.SerializationInfo info,
    System.Runtime.Serialization.StreamingContext context) :
        base(info, context) { }

    // Override ToString for RangeArrayException.
    public override string ToString()
    {
        return Message;
    }
}
// An improved version of RangeArray.
class RangeArray
{
    // Private data.
    int[] a; // reference to underlying array
    int lowerBound; // smallest index
    int upperBound; // largest index

    // An auto-implemented, read-only Length property.
    public int Length { get; private set; }

    // Construct array given its size.
    public RangeArray(int low, int high)
    {
        high++;
        if (high <= low)
        {
            throw new RangeArrayException("Low index not less than high.");
        }
        a = new int[high - low];
        Length = high - low;
        lowerBound = low;
        upperBound = --high;
    }

    // This is the indexer for RangeArray.
    public int this[int index]
    {
        // This is the get accessor.
        get
        {
            if (ok(index))
            {
                return a[index - lowerBound];
            }
            else
            {
                throw new RangeArrayException("Range Error.");
            }
        }
        // This is the set accessor.
        set
        {
            if (ok(index))
            {
                a[index - lowerBound] = value;
            }
            else throw new RangeArrayException("Range Error.");
        }
    }

    // Return true if index is within bounds.
    private bool ok(int index)
    {
        if (index >= lowerBound & index <= upperBound) return true;
        return false;
    }
}
// Demonstrate the index-range array.
class RangeArrayDemo
{
    static void Main()
    {
        try
        {
            RangeArray ra = new RangeArray(-5, 5);
            RangeArray ra2 = new RangeArray(1, 10);

            // Demonstrate ra.
            Console.WriteLine("Length of ra: " + ra.Length);
            for (int i = -5; i <= 5; i++)
                ra[i] = i;
            Console.Write("Contents of ra: ");
            for (int i = -5; i <= 5; i++)
                Console.Write(ra[i] + " ");
            Console.WriteLine("\n");

            // Demonstrate ra2.
            Console.WriteLine("Length of ra2: " + ra2.Length);
            for (int i = 1; i <= 10; i++)
                ra2[i] = i;
            Console.Write("Contents of ra2: ");
            for (int i = 1; i <= 10; i++)
                Console.Write(ra2[i] + " ");
            Console.WriteLine("\n");
        }
        catch (RangeArrayException exc)
        {
            Console.WriteLine(exc);
        }

        // Now, demonstrate some errors.
        Console.WriteLine("Now generate some range errors.");
        // Use an invalid constructor.
        try
        {
            RangeArray ra3 = new RangeArray(100, -10); // Error
        }
        catch (RangeArrayException exc)
        {
            Console.WriteLine(exc);
        }

        // Use an invalid index.
        try
        {
            RangeArray ra3 = new RangeArray(-2, 2);
            for (int i = -2; i <= 2; i++)
                ra3[i] = i;
            Console.Write("Contents of ra3: ");
            for (int i = -2; i <= 10; i++) // generate range error
                Console.Write(ra3[i] + " ");
        }
        catch (RangeArrayException exc)
        {
            Console.WriteLine(exc);
        }
    }
}

/* Output
 
Length of ra: 11
Contents of ra: -5 -4 -3 -2 -1 0 1 2 3 4 5 

Length of ra2: 10
Contents of ra2: 1 2 3 4 5 6 7 8 9 10

Now generate some range errors.
Low index not less than high.
Contents of ra3: -2 -1 0 1 2 Range Error.

*/

در مثال بالا، هنگامی‌که range error اتفاق می‌افتد، کلاس RangeArray یک exception از نوع RangeArrayException پرتاب می‌کند. دقت کنید که در سه قسمت کلاس RangeArray ممکن است خطا به‌وجود آید: در get indexer accessor، در set indexer accessor و در RangeArray constructor. همان‌طور که می‌بینید، constructor های کلاس RangeArray در بدنه‌شان هیچ‌گونه کدی قرار نگرفته است و فقط argument ها را از طریق base به Exception می‌فرستند.

به مثال زیر توجه کنید:

using System;
public class ReThrowDemo
{
    public static void Main()
    {
        try
        {
            Console.WriteLine("Trying in Main() method");
            MethodA();
        }
        catch (Exception ae)
        {
            Console.WriteLine("Caught in Main() method --\n {0}",
            ae.Message);
        }
        Console.WriteLine("Main() method is done");
    }
    public static void MethodA()
    {
        try
        {
            Console.WriteLine("Trying in method A");
            MethodB();
        }
        catch (Exception)
        {
            Console.WriteLine("Caught in method A");
            throw;
        }
    }
    public static void MethodB()
    {
        try
        {
            Console.WriteLine("Trying in method B");
            MethodC();
        }
        catch (Exception)
        {
            Console.WriteLine("Caught in method B");
            throw;
        }
    }
    public static void MethodC()
    {
        Console.WriteLine("In method C");
        throw (new Exception("This came from method C"));
    }
}

/* Output
 
Trying in Main() method
Trying in method A
Trying in method B
In method C
Caught in method B
Caught in method A
Caught in Main() method --
 This came from method C
Main() method is done
 
*/

در این برنامه، فراخونی متدها و در نهایت پرتاب شدن exception، موجب به‌جود آمدن خروجی بالا می‌شود.



نویسنده / مترجم : مسعود درویشیان

علاقه مند به موسیقی و برنامه نویسی بازی


۱۶ دیدگاه برای این نوشته ثبت شده است


  1. mohsen
    ۲۱ دی ۱۳۹۲

    سلام
    خیلی ممنون از تمام توضیحاتی که درمورد کنسول دادید ولی اگه امکانش هست ویندوز واموزش بدید خیلی ممنوننم




  2. میلاد
    ۲۶ دی ۱۳۹۲

    با سلام و خسته نباشید
    بسیار ممنون از زحماتتون.
    خیلی مطالب کاربردی بودن برای من.
    میخواستم بدونم که قسمت بعدی چه زمانی منتشر میشه؟




  3. مسلم
    ۲۸ دی ۱۳۹۲

    خیلی خیلی تشکر مهندس،
    آموزش خیلی کاملیه! دستتون درد نکنه!
    خیر ببینی انشاء الله




  4. علی ابراهیمی
    ۲۸ دی ۱۳۹۲

    سلام و تشکر از زحماتتون
    چرا دیگه ادامه نمی دید؟




  5. milad
    ۲۹ دی ۱۳۹۲

    با سلام
    مهندس جان تعداد زنگهای کلاس سی شارپ چند تاست؟




  6. فرزاد
    ۲۹ دی ۱۳۹۲

    سلام خیلی ممنون.




  7. صالح
    ۳۰ دی ۱۳۹۲

    سلام
    خوب بود مر۳۰




  8. علی ابراهیمی
    ۸ بهمن ۱۳۹۲

    سلام استاد
    یک ماه از انتشار آخرین زنگ سی شارپ می گذره
    می خواستم بدونم زنگ بعدی کی منتشر می شه؟




  9. bijan
    ۱۲ بهمن ۱۳۹۲

    منتظرتون هستیم و ممنون به خاطر آموزشهای شما




  10. امیراحمدادیبی
    ۲۲ بهمن ۱۳۹۲

    به خدا این کارتون از هر کار دیگه ایی ثوابش بهتره امید وارم هر چی از خدا میخواید بهتون بده من که واقعا خوشم اومد و کارتون خیلی هم تمیز و بی عیب و نقص




  11. امیراحمدادیبی
    ۲۲ بهمن ۱۳۹۲

    به خدا این کارتون از هر کار دیگه ایی ثوابش بهتره امید وارم هر چی از خدا میخواید بهتون بده من که واقعا خوشم اومد و کارتون خیلی هم تمیز و بی عیب و نقص….




  12. محمد
    ۲۲ بهمن ۱۳۹۲

    سلام.با تشکر از زحمات شما. ادامه مقالات از کی شروع میشه؟




  13. kamal
    ۲۷ بهمن ۱۳۹۲

    با عرض سلام و تشکر فراوان به جهت آموزش های فوق العاده و کاربردیتون
    ببخشید من می خواستم بدونم که آموزش بعدی شما کی توی سایت قرار خواهد گرفت؟
    من که بی صبرانه منتظر رسیدن آموزش های بعدی شما هستم
    باتشکر فراوان




  14. مسلم
    ۲۳ اسفند ۱۳۹۲

    من از همین الان تا …. ، مدیون شما هستم
    واقعا فکر میکردم هیچ وقت نتونم سی شارپ رو با کنسول
    یاد بگیرم.
    بدم میاد از برنامه نویس هایی که ، برنامه نویسی رو با نقاشی
    کردن اشتباه میگیرن و فقط از کدهای آماده و template ها و …
    استفاده میکنن.
    من حرفه ایی پایتون کار میکنم و انشالله قصد دارم مثل شما
    برای پایتون هم “زنگ پایتون” درست کنم و مثل شما آموزشش بدم
    یک دنیا ممنونم از شما
    در پناه حق




  15. ترجمه تخصصی
    ۳ اسفند ۱۳۹۳

    ممنونم سایتتون عالیه.



دیدگاه خود را بنویسید





نشانی ایمیل شما منتشر نخواهد شد.

کامنت های شما بعد از تأیید توسط نویسنده وبلاگ، منتشر خواهند شد.

لطفا دیدگاهتان تا حد امکان مربوط به پست بالا باشد. اگر حرف دیگری دارید و یا قصد تماس با من را دارید، از فرم تماس استفاده کنید.

شما میتوانید با مراجعه به سایت گراواتار یک آواتار اختصاصی برای خود تعریف کنید، تا در کنار نام شما نمایش داده شود

برای قرار دادن کدهای نمونه می توانید از تگ های [php] ، [html] ، [css] و [js] استفاده کنید.
به عنوان مثال کدهای php را می توان به صورت زیر قرار داد:
[php] var $whoLoveIranians = "WebTarget!"; [/php]



کلیه حقوق مادی و معنوی برای وب سایت وب تارگت محفوظ است ©2017 webtarget.ir

استفاده از مطالب وب سایت در سایر وب سایت‌ها و نشریات چاپی با ذکر منبع آزاد است.