فیلتر استثناها در 6.0 #C

سه شنبه 24 شهریور 1394

در این مقاله، درباره یکی دیگر از امکانات مهم 6.0 #C با عنوان فیلتر کردن استثنائات بحث خواهیم کرد.

فیلتر استثناها در 6.0  #C

فیلتر استثنائات:

Exception filtering هیچ چیز خاصی نیست جز شرط هایی که به بلاک Catch اضافه می شوند. اجرای بلاک Catch به این شرط ها بستگی دارد. به این مثال توجه کنید.

در 5.0 #C، برای نمایش یک پیام مناسب به کاربر، کدی شبیه کد زیر براساس کدهای وضعیت http یا همان (http status) که به صورت تصادفی ایجاد می شوند، به کار می بردیم.

    using System;  
    using static System.Console;  
      
    namespace NewInCSharp  
    {  
        class Program  
        {  
            private static void Main(string[] args)  
            {  
                Random random = new Random();  
                var randomExceptions = random.Next(400, 405);  
                WriteLine("Generated exception: " + randomExceptions);  
                Write("Exception type: ");  
      
                try  
                {  
                    throw new Exception(randomExceptions.ToString());  
                }  
                catch (Exception ex)  
                {  
                    if(ex.Message.Equals("400"))  
                        Write("Bad Request");  
                    else if (ex.Message.Equals("401"))  
                        Write("Unauthorized");  
                    else if (ex.Message.Equals("402"))  
                        Write("Payment Required");  
                    else if (ex.Message.Equals("403"))  
                        Write("Forbidden");  
                    else if (ex.Message.Equals("404"))  
                        Write("Not Found");  
                }  
      
                ReadLine();  
            }  
        }  
    }  

در این کد، یک کد استثنای تصادفی به نام RandomException ایجاد کردیم. در بلاک Catch، یک پیام خطای مناسب مربوط به کد استثنا نمایش می دهیم.

حال با Exception filtering نیز می توانیم همین کار را انجام دهیم اما نحوه نگارش آن مقداری متفاوت است. علاوه بر ایجاد بلاک Catch و بررسی اینکه کدام شرط نوشته شده دچار استثنا (exception) شده است، می توانیم بلاک Catchهای خاصی تعریف کنیم. به کد زیر توجه نمایید.

    using System;  
    using static System.Console;  
      
    namespace NewInCSharp  
    {  
        class Program  
        {  
            private static void Main(string[] args)  
            {  
      
                Random random = new Random();  
                var randomExceptions = random.Next(400, 405);  
                WriteLine("Generated exception: " + randomExceptions);  
                Write("Exception type: ");  
      
                try  
                {  
                    throw new Exception(randomExceptions.ToString());  
                }  
                catch (Exception ex) when (ex.Message.Equals("400"))  
                {  
                    Write("Bad Request");  
                    ReadLine();  
                }  
                catch (Exception ex) when (ex.Message.Equals("401"))  
                {  
                    Write("Unauthorized");  
                    ReadLine();  
                }  
                catch (Exception ex) when (ex.Message.Equals("402"))  
                {  
                    Write("Payment Required");  
                    ReadLine();  
                }  
                catch (Exception ex) when (ex.Message.Equals("403"))  
                {  
                    Write("Forbidden");  
                    ReadLine();  
                }  
                catch (Exception ex) when (ex.Message.Equals("404"))  
                {  
                    Write("Not Found");  
                    ReadLine();  
                }  
            }  
        }  
    }  

اما تفاوت این دو چیست. زمانی که تنها از یک بلاک Catch استفاده می کنیم، حالت اجرای کنونی گم می شود و پیدا کردن قسمتی از کد که باعث خطا شده سخت می شود. اما در exception filtering ما دقیقا همان جایی قرار می گیریم که باید قرار بگیریم.

همانطور که می بینید، Exception filtering خوب است و در آن هر بلاک را با توجه به فیلتری که روی آن اعمال می کنیم، ایجاد می کنیم. یک اشتباه کوچک می تواند به طور کلی معنی آن exception را تغییر دهد. این فیلترها بر اساس یک مقدار بولین کار می کنند که ممکن است از هر یک بلاک های کد ارسال شود و معانی مختلفی به exception بدهد. برای مثال:

using System;  
using System.Net.Http;  
using System.Threading.Tasks;  
using static System.Console;  
  
namespace NewInCSharp  
{  
    class Program  
    {  
       private static void Main(string[] args)  
        {  
            Task.Factory.StartNew(GetWeather);  
            ReadLine();  
        }  
  
        private static async void GetWeather()  
        {  
            string customErrorMessage;  
            HttpClient client = new HttpClient();  
  
            try  
            {  
                HttpResponseMessage httpResponseMessage = await client.GetAsync("http://api.openweathemap.org/data/2.5/weather?q=NewYorK");  
                WriteLine(httpResponseMessage);  
            }  
            catch (Exception ex) when (DoASillyMistake(ex.Message, out customErrorMessage))  
            {  
                WriteLine(customErrorMessage);  
            }  
        }  
  
        private static bool DoASillyMistake(string exceptionMessage, out string customErrorMessage)  
        {  
            if (exceptionMessage.Equals("An error occurred while sending the request."))  
            {  
                customErrorMessage = "Unauthorized.";  
                return true;  
            }  
            else  
            {  
                customErrorMessage = "Bad Gateway.";  
                return true;  
            }  
        }  
    }

شاید این مثال مسخره به نظر بیاید، اما فرض کنید که این یک درخواست باشد که یک سرویس در حال اجرا است یا خیر، که می تواند به دو دلیل باشد، اول اینکه سرویس در حال اجرا نباشد به عبارت دیگر up نباشد (Bad Request) و دیگری اینکه کاربر نیاز دارد قبل از دسترسی به سرویس احراز هویت کند(Unauthorized)،در این کد ما مطمئن هستیم که اگر یک Bad Request داشته باشیم، پیام خطایی مانند پیام زیر از طریق HttpClient ارسال می شود.
An error occurred while sending the request.

به همین صورت برای پیام های دیگر، درخواست Unauthorized را در نظر بگیرید. اگر به متد      (DoASillyMistake(string exceptionMessage, out string customErrorMessage توجه کنید، می بینیدکه این اشتباه واقعا مسخره است. به کاربر نشان داده ایم که مجاز به دسترسی به سرویس نیست، درصورتی که پیام مناسب "Unauthorized" می باشد چرا که آدرس سرویس معتبر نمی باشد (حرف 'r' در کلمه weather جا افتاده است). به این صورت، کاربر به دنبال فرایند ثبت نام و دسترسی به سرویس خواهد بود بدون اینکه از اشتباه ما آگاه باشد. جالب تر اینکه اگر بخواهیم کاربر را ثبت نام کنیم، از این پس خطای "Bad Request" برای کاربر نمایش داده می شود. بنابراین زمان استفاده از exception filtering باید به این نکات دقت کنیم.

برای مثال می توانیم یک متد فیلتر به پروژه اضافه کنیم که پیام خطاها را log بزند و مقدار false برگرداند، بنابراین log شامل Exception مناسب و همچنین اجرای برنامه در بلاک Catch پایان پیدا نمی کند.

آموزش سی شارپ

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان
  • C#.net
  • 1k بازدید
  • 3 تشکر

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید