الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

نقاش حول أساليب ال Exception

مغلق
بدأه هاني الأتاسي في 12 أكتوبر 2005 · 10 رد · 2,510 مشاهدة · في قسم تكنولوجيا Microsoft .NET العام
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بصراحة لا أريد أن أشرح هذا الموضوع وهو كيفيه استخدام والاستفادة من ال Exceptions في دوتنيت .. وماهو أفضل الاساليب في استخدامها .. لأني أعرف إذا كتبت الموضوع كامل فالقليل سوف يقرئه أو سوف يكون الموضوع ممل .. لذلك سوف أفتح هذا الموضوع للنقاش ومن ردودكم سوف نتاقش وبالنهاية نقوم بالتلخيص ..

أولا أحب أن تعطوني بعض الأمثلة الحقيقة التي واجهتموها في مشاريعكم بحيث استخدم exceptions او صنعتم نوع exception .. وأيضا ماهي وجهة نظركم عن استخدام ال exception ومتى نستخدمها ومتى لا نستخدمها ؟؟

Coding on the Cloud and for the Cloud!

My Blog

#2

كويس انك طرحت الموضوع ده يا أخ هاني , وأنا هـ بص عليه شويه وهحاول أرد عليك , ان شاء الله ,,,

تم تعديل هذه المشاركة بواسطة hazzoom في 14 أكتوبر 2005 في 05:57

#3

أشكركم على طرح هذا الموضوع الهام.

وأحب أن أضيف هنا.

هناك العديد من الأخطاء التي تحصل أثناء التنفيذ.

ولكن الأساليب البرمجية المستخدمة لحلها شائعة قبل ظهور ال Exception وفي هذه الحالة لا يتوجب علينا إستخدامه

مثل قراءة الملفات فأنا لا أحتاج إلى Exception ليخبرني بنهاية الملف. لعلي أذكر هنا مثال (في نفس هذا الموضوع ولكن في مشاركة أخرى)

لكن عندما تضطرب الأساليب حول حل مشكلة معينه عند التنفيذ نستخدم ال Exception

وهي كثير وكذلك المشاكل التنفيذية الجديدة.

وشكراً

#4

السلام عليكم ورحمة الله وبركاته...

في الحقيقة هذا الموضوع دائماً يحيرني ويجعلني (معبوط) في كيفية ومكان معالجة الاستثناءات وهنا بعض الأماكن التي أستخدمها فيها:

1 - عند تنفيذ عملية على قاعدة البيانات

try
{
     conn.Open();
     // Do something Here
}
catch (Exception ex)
{
    // catch exception here
}
finally
{
    conn.close();
}

2 - عند تحويل قيمة نصية إلى رقم:

try
{
    i = Convert.ToInt32(SOME_STRING_VALUE);
}
catch
{
}

بالمناسبة ألا يوجد في C# دالة تجعلني أفحص هل القيمة يمكن تحويلها إلى قيمة رقمية أم لا...

سؤال: كيف أستطيع بناء Class خاص ببرنامجي مهمته استقبال جميع الأخطاء التي تحدث ضمن برنامجي ( أرجو التركيز على موضوع الويب ) وخاصة تلك الغير متوقعة أبداً.

#5

بدل أن أقول افعل كذا سأقول لا تفعل كذا:

1- لا تجعل جملة (امسك) أو catch فارغة.

trc{
conn.open();
}
catch(Exception e){}//أكبر خطأ يمكن أن تقع فيه،،، بل اكتب 
[code]
catch(Exception e){Console.write(e);}مثلا

2- لا تفعل هكذا:

public class Person<T extends Exception>{
public String getName()throws T{
return name;
}
}
public static void main(String []args){
try{
Person <? extends NullPointerException>p=new Person<NullPonterException();
p.getName();
}
catch(Exception e){
e.printStackTrace();
}

إذا لم تفهم المثال فهذا أفضل!!

3- إذا كانت الشفرة مسؤولة عن عمل شيء معين في منطق برنامجك، كإضافة مكافأة للموظف:

public class Person{
public void reward(double amount)throws NotWorthItException{
if(amount>1000)throw new NotWorthItException();
add(amount);
}
}

أما في شفرة الواجهة فاستعمل trycatch.

try{
double value=Double.parseDouble(text.getText());
p.reward(1234);
catch(CannotBeParsedException e){
JOptionPane.showMessageDialog("Please enter a valid number);
}
catch(NotWorthItException e){
JOpttionPane.showMessageDialog("The Amount is too large probably, or the person is not worth the reward unfortuanitly.");
}

في المثال السابق أحببت أن أبين متى تستخدم جملة throws ومتى تستخدم trycatch،،

هذه كبداية،، بالتوفيق!

#6

أحب أن أنبه أيضا عن شئ ضروري في عملية الـ Catch وهو البدء بعمل Catch للـ Exceptions التي تتوقع أن تحدث أولا والتي تكون أكثر خصوصيه ثم بعد ذلك عمل Catch للـ Exceptions العامه.

هذه الطريقه لها اسم ولكني لا أتذكره :)

مثلا في المثال الخاص بفتح الاتصال بقاعدة بيانات ... يجب أن تمسك الـ SqlException مثلا أولا أو OleDbException حسب الـ Provider قبل أن تمسك الـ Exception العام ::

tyr
{
conn.Open();
}
catch(SqlException sqle)
{
// do someting with sqle
}
catch(Exception exc)
{
//do something with exc
}
finally
{
// for cleanup or user interface or....
}

أيضا في عمل Convert فان الأولى أن تمسك FormatException أولا ::

try
{
 i = Convert.ToInt32(SOME_STRING_VALUE);
}
catch(FormatException fe)
{
// do someting with fe
}
catch(Exception exc)
{
// do something with exc
}

وهكذا .... مثلا في العمليات الرياضيه مثل القسمه تمسك DivideByZeroException أولا ثم ArithmeticException ثم الـ Exception العادي أو قبله تسمك Exception من صنعك يكون أكثر خصوصيه مثلا وهكذا.

موضوع Handling Exceptions هو من الأمور الرائعه في الـ CLR ولذلك يجب أن ننتبه له جيدا لأنه يعتبر من أبرز مميزات الدوت نت.

#Read

http://MoutazShams.blogspot.com

projects003.gif

أعتذر عن التغيب هذه الأيام نظرا للانشغال المريب

#7
اقتباس
هذه الطريقه لها اسم ولكني لا أتذكره

do u mean Exception Handling Hierarchy

#8

سوف أجاوب على بعض الأخوة وسوف أترك لب النقاش لموضوع لاحق ، وأنتظر المشاركة من المزيد من الأخوة ..

hazzoom

منتظر مشاركتكك

mossa

اقتباس
ولكن الأساليب البرمجية المستخدمة لحلها شائعة قبل ظهور ال Exception وفي هذه الحالة لا يتوجب علينا إستخدامه

هذا تحليل خاطئ ، يوجدد العديد من الأساليب القديمة في معالجة الأخطاء ييفضل أن نتعامل بال Exceptions معها .. قرائة بايت من نهائة الملف لا يعتبر خطأ بالأساس لذلك لا تحتاج Exception

اسماعيل

بالنسبة لموضوع الدالة في سي# من أجل فحص هل يمكن تحويل القيمة من غير Exception فقد تم اضافتها في الاصدار الثاني من دوت نيت . وهي :

public static bool TryParse (
	string s,
	out int result
)

أقول الآن بشكل مختصر أن انشاء ال Exception جدا بطيئ ومكلف ، لذلك تم اضافة TryParse من أجل السرعة ، وسوف أتكلم عن البطئ لحاقا بشئ من التفصيل ..

Coding on the Cloud and for the Cloud!

My Blog

#9

السلام عليكم

أود أن أضيف أنه يمكن عمل ما أشار اليه الأخ معتز بطريق أخري , بحيث يمكن عمل تداخل في كود الـ Try أو مايسمي Nesting هكذا :

  Try
            'operation here
            Dim x, y, z As Integer
            y = 0
            x = 1
            z = x / y
        Catch ex1 As OverflowException
            Try
                'operation here
                MsgBox(ex1.Message)
            Catch ex2 As DivideByZeroException
                MsgBox(ex2.Message)
            End Try
        End Try

كما أود أن أذكر نوع من الـ Exception قد يكون شائعا عند التعامل مع المصفوفات وهو IndexOutOfRangeException ,

ويحدث عند استدعاء عنصر غير موجود أو بمعني أدق خارج حدود المصفوفه ,

        Try
            Dim arr() As String
            Dim txt As String = "hazem-mohammed"
            arr = Strings.Split(txt, "-")
            arr.Reverse(arr)
            MsgBox(arr(2))
        Catch ex As IndexOutOfRangeException
            MsgBox(ex.Message, MsgBoxStyle.Critical)
        End Try

تم تعديل هذه المشاركة بواسطة hazzoom في 15 أكتوبر 2005 في 02:31

#10

شكرا للأخوة على المشاركة :)

ولي تعليق على الأمثلة التي وضعتوها ..

لاحظت الجميع يقوم بمسك ال Exceptions ويطبعها أو شئ من هذا القبيل ولكن لم يذكر لماذا لم يدع ال Exception تكفي مسارها إلى التابع الأب وهكذا .

من أساليب مسك ال Exception هو أنك تمسك فقط ال Exceptions التي تتوقع أن ترسل اليك . أما التي لا تتوقعها فلا تحاول أبدا امساكها ، وإذا مسكتها لعمل شئ ما بها كطباعتها أو تسجيلها في ملف ، يجب عليك أن ترسلها مرة أخرى (عن طريق throw;) لتكمل مسارها إلى التابع الأب وهكذا.

مثلا إذا كنت تقوم بعملية على ملف في برنامجك ، فأنت تفترض أن الملف سوف يكون موجودا في الجهاز، ولن تتوقع أن يكون الملف قد مسح ، ففي هذه الحالة ليس من الجيد أن تمسك بهذه الException ولكن تجعلها تذهب إلى تابع الأب وهكذا ..

وبالتالي من الأمور غير المستحسنة أن تمسك بجميع ال Exception في تابعك .. ولكن خصص في هذا مثل امساك IOException او OverflowException ... إذا حاوبت أن تمسك الجميع (Exception) فقد تمسك مثلا InvalidArgumentException التي تعتبر في معظم الأحيان عبارة عن خطأ برمجي قمت أنت به ، ويفضل في هذه الحالة من هذه ال Exception أن تغلق البرنامج . أمثلة أخرى تكمن إذا مثلا قام أحد المخترقين في اختراق برنامجك ففي هذه الحالة سوف يتم ارسال Exception ما ولا تريد ان تمسك بها لأن البرنامج هنا في حالة غير معروفة.

شرح بسيط عن بناء الكلاس..

إذا أردنا بناء كلاس ما ، بشكل عام يجب أن نفكر بال Exception كالتالي:

1- عندما نقوم بتصميم كلاس معين فإننا نتخيل كيف سوف يستخدم هذا الكلاس من قبل الآخرين ، ونقوم بتعريف عدة توابع فيه.

2- كل تابع سوف يقوم بأداء مهمة ما. وإذا كان التابع لا يستطيع القيام بمهمته فعليه أن يمرر لنا بال Exception ..

على سبيل المثال إذا كنا نصمم التابع Login فهذا التابع من اسمه يدل على أنه سوف يقوم بعملية تسجيل الدخول . الآن لو قمنا بتمرير كلمة مستخدم وسر خاطئين فالتابع بالتالي لا يمكنه من القيام بمهمته فالمفروض أن يحصل هنا هو أن التابع سوف يمرر لنا بال Exception .

ماذا لو أردنا تصميم تابع اسمه DoesUserExist (أي هل المستخدم موجود أو مسجل) . فعند تمرير اسم كان صحيحا، فالتابع سوف يرجع قيمة True أما إذا مررنا اسما خاطئا فالتابع سوف يرجع False . على سبيل المثال كان التابع يقرأ بياناته من قاعدة بيانات ، والسيرفر الذي نقرأ منه كان مغلق ففي هذه الحالة التابع لا يستطيع أن يقوم بمهمته ومنها عليه أن يمرر لنا بال Exception .

فوائد استخدام ال Exceptions

* انها طريقة تتيح لنا كتابة كود صلب ، سهل المراجعة ، يدعم البرمجة في OOP .. توابع الOOP كلها يفترض أنها سوف تنجح (كما رأينا في الأمثلة السابقة) لذلك كان لا بدم من طريقة أفضل من ارجاع Error code .

* الكود المسؤول عن عملية التنضيف cleanup code يتم وضعه في محل واحد ، وبالتالي سوف يكون منفصل عن بقية الكود الأساسي في البرنامج ويسهل قرائته

* (إلى شئ من الصحة) قد يكون الكود الذي يستخدم Exceptions Handling اسرع من طريقة الكود التي تفحص كود الخطأ بعد الانتهاء من كل تابع.

* سرعة معرفة المشكلة واصلاح المشكلة . وذلك لأن ال Exceptions تحتوي على معلومات اضافية تسهل من معرفة سبب المشكلة ، مثل التوابع التي تم استدعائها وصيغة نصية للمشلة .

* إذا حصل Exception فلا يمكن تجاهلها ، على العكس من الكود القديم فيمكن أن يخطأ التابع ولا نتفقد من كود الخطأ.

بنسبة إلى أداء ال Exception ..

إذا راجعنا تاريخ ال Exception لوجدناها قد تم اضافتها قديما في وندوز SEH أو Structured Exception Handling وكانت متاحلة لمبرمجي سي و سي++ . لكن المبرمجين لم يستخدموها لعدم المامهم بها . لقد تم برمجة ال Exceptions في النظام نفسه في النواه بحيث أن كل Exception عبارة عن Interrupt وينتج عنه تحويل من بيئة المستخدم إلى نواه النظام ومن ثم العودة . وهذه العملية بذاتها جدا بطيئة .

فريق ال dot-net وجد أنه من الأفضل استخدام التقنية الموجودة في وندوز حاليا من أجل ال Exceptions وذلك من أجل التوافقية . ولذلك يجب الحذر من عدم الافراط من استخدام ال Exceptions .

طبعا يمكننا التحايل قليلا من أجل اسراع الكود الذي نريد . علينا فقط تغير اسم التابع فمثل بدلا من أن يكون اسم التابع Parse نجعل اسمه TryParse .

فكما ذكرت للأخ اسماعيل أنه تم اضافة التابع TryParse في دوت نيت 2 ، من أجل ارجاع قيمة العدد المخزن في سلسلة رقمية مثلا. لاحظ التابعين التاليين ..

int Parse(string s);
bool TryParse(string s, out int n);

التابع الأول المفروض أن يرجع قيمة عدد ، ولكن إذا لم يستطع أن يرجع العدد لأن السلسلة تحتوي على أحرف مثلا فالتابع سوف يمرر لنا ال Exception . لذلك يمكن اضافة تابع آخر اسمه TryParse أي حاول أن تقوم بالتحويل . إذا كانت قيمة السلسلة خاطئة فالتابع سوف يعيد false وهي تعتبر قيمة سليمة ولا يوجد داعي لل exception هنا .

طبعا يمكن أن تجادلني وتقول التابع الثاني يشابه طريقة البرمجة القديمة في سي .. ولكني أقول أن التابع الجديد ليس عليه أي غبار لأن اسمه TryParse وليس Parse ، والدوت نيت تحتوي على التابعين ويمكن استخدام التابع الثاني إذا أردت السرعة . طبعا سوف تجد امثلة قليلة في الدوت نيت بحيث ترى اسم التابع يسبق ب Try . ويفضل باتباع هذه الطريقة إذا شعرت أن التابع سوف يتم استدعائه كثيرا ومعظم الأحيان سوف يفشل في عمله.

بشكل عام يجب أن تنشئ وترسل Exception في كودك في الحالات التالية:

* إذا كان تابعك لا يمكنك اكمال العمل الذي يجب أن يقومه

* يجب أن تفكر ماهو أفضل نوع Exception تريد أن ترسله . يفضل دائما أن ترسل نوع Exception قمت أنت بتعريفه بحيث يرث من النوع Exception . من النادر أنك سوف تستخدم نوع exception مسبق التعريف في دوت نيت (ك InvalidOperationException و ArgumentNullException و ...)

* يجب أن تضع رسالة تبين نوع الخطأ في ال exception التي سوف ترسلها . هذه الرسالة يجب أن تكون جملة صحيحة كاملة مع نقطة في نهاية الجملة :)

* طبعا دوت نيت تنشئ وترسل exception في عدة حالات

- معظم التوابع إذا لم تستطع أن تعمل ما يجب عمله (راجع MSDN)

- القسمة على 0 وهي DivideByZeroException

- حماية SecurityException و ذاكرة OutOfMemoryException

هناك امور أخرى سوف أتطرق إليها عن ال Exceptions ، ولكن أنتظر بعض المشاركة ..

Coding on the Cloud and for the Cloud!

My Blog

هذا الموضوع مغلق.

مواضيع مشابهة