منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب

نسخة كاملة : الدرس الخامس والعشرون - الأخطاء واقتناصها
أنت حالياً تتصفح نسخة خفيفة من المنتدى . مشاهدة نسخة كاملة مع جميع الأشكال الجمالية .
كاتب الموضوع : أحمد جمال

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

سنتعرف في درس اليوم على الأخطاء وكيفية اقتناصها وتفاديها ، معاني رسائل الخطأ واشهر الاخطاء وخلافه ، ولكن قبل البداية نحتاج لإن نوضح أقسام الأخطاء التي تحصل في اي برنامج :

Syntex Errors - الأخطاء النحوية :
هذا النوع من الاخطاء هو الاسهل ، وفي Advanced Programming Environments مثل ال Visual Studio , netbeens ... etc ، يتم اكتشاف هذه الأخطاء فورياً ، مثال هذا الخطأ كتابة الجملة التالية :

if x.Nome = somevalue

بالطبع ستجد رسالة خطأ قبل التنفيذ تخبرك بأن الخاصية Nome غير موجودة ، مثل هذه الأخطاء هي الاسهل ويتم اكتشافها من خلال بيئة لغة البرمجة التي تعمل عليها ، وفي Visual Studio .net 2008 اصبحت رسائل الخطا واضحة للغاية ويمكن تفسيرها بسهولة وحلها بهذه الطريقة ، لكننا للاسف نجد الكثير من الاسئلة حول برامج لا تعمل بها خطأ واضح ، لماذا ؟ لا أدري

Logical Errors - الأخطاء المنطقية :
هذا النوع من الأخطاء هو الأصعب ، فعلى صعيد كتابة الكود ربما لا يوجد خطأ نحوي ولكنه خطا منطقي يظهر عند التنفيذ ، ابسط مثال على هذا الخطأ هو كتابة كود كالتالي :

Byte x = 100000

طبعاً تعرف ان حدود النوع Byte اصغر من هذا الحد ، ولكن في الاصدارات القديمة لم يكن هذا ليظهر خطأ حيث ان الجملة مكتوبة نحوياً كما ترى . امثلة على هذا الخطأ اسناد قيمة ل object قبل عمل new له .. الخ .

لكن مع اصدارات فيجوال ستوديو الجديدة ، اصبحت مثل هذه الأخطاء تظهر مباشرة ، بل ان هناك انواعاً اصعب من ال Logic Errors اصبح الفيجوال ستوديو قادر على اكتشافها على شكل warnnings .

لن نذهب بعيداً ، سنبدأ بتقسيم ال Logical Errors وهي الأخطاء الأهم إلى ثلاثة أنواع اساسية :

User Error :
أخطاء تنتج من استخدام البرنامج ، لو افترضنا المثال السابق ل Byte نقوم فيه بتخزين عمر المستخدم ، لكن المستخدم قام بادخال رقم 10 الاف ، هذا الخطأ من المستخدم سيتسبب في المشاكل لك فيما لو لم تكن قد اضفت شرط التأكد من عدم تجاوز العمر لحد معين ، ايضاً ادخال بيانات نصية في خانة العمر وخلافه تندرج تحت اسم أخطاء المستخدم .

Exceptions :
النوع الأشهر من الأخطاء ، محاولة فتح ملف او قاعدة بيانات غير موجودة مثلاً حيث لم يتم تحميلها بصورة صحيحة ، محاولة قراءة بيانات من قاعدة البيانات في حين انها تساوي null بدون استخدام nullable type ، محاولة الكتابة إلى ملف نصي ReadOnly ، وخلافه من الأخطاء المشهورة .

Bugs :
اكثر الأخطاء شهرة ، لا يمكن حصرها ولا عدها ، وتوجد في جميع البرامج بما فيهم نسخة الويندوز التي تستخدمها ، في العادة لن يخلو برنامج منها ولكننا نحاول تفاديها قدر المستطاع ، قد تحدث بسبب نسيان حذف متغير او قراءة متغير من قيمة موجودة اصلاً في الذاكرة ونحن نظن انها قيمة فارغة ... الخ ، هذه الأخطاء قد لا تظهر ل 99% من المستخدمين ولكنا تظهر لمستخدم واحد فقط ، لذا في العادة تكون هناك عدة نسخ تجريبية من اي برنامج لمحاولة معرفة اماكن امثال هذه الأخطاء وتعديلها قبل طرح النسخة الرسمية .

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

قبل ان ندخل في الدرس ، ربما ترغب في الاطلاع على الدرس التالي للاستاذ تركي العسيري - بعيداً عن انه للفيجوال بيسك 6 ولكنه يوضح معاني الأخطاء .
http://vb4arb.com/vb/showthread.php?1605

الدرس التالي للاخ محمد سامر سلو ، حول الاستثناءات والأخطاء :
http://vb4arb.com/vb/showthread.php?803

يتبع ...
الكلاس System.Exception :

الكلاس المختص في .net بالتعامل مع الأخطاء التي تحدث في النظام ، في الواقع فإن أي خطأ يرسل للنظام ثم يقوم النظام بارساله إلى ال CLR ، والذي بدوره يخول System.Exception للتعامل مع هذا الخطا ، محتويات هذا الكلاس بالشكل التالي :


كود :
[FONT=Tahoma]public class Exception : ISerializable, _Exception
{
// Public constructors
public Exception(string message, Exception innerException);
public Exception(string message);
public Exception();
// Methods
public virtual Exception GetBaseException();
public virtual void GetObjectData(SerializationInfo info,
StreamingContext context);
// Properties
public virtual IDictionary Data { get; }
public virtual string HelpLink { get; set; }
public System.Exception InnerException { get; }
public virtual string Message { get; }
public virtual string Source { get; set; }
public virtual string StackTrace { get; }
public MethodBase TargetSite { get; }
}[/FONT]


سنحاول التعرف على الخصائص والطرق الاساسية لهذا الكلاس :

Message : رسالة الخطأ الحاصلة .
Source : ملف الاسمبلي الذي قام بعمل throw لهذا الخطأ .
HelpLink : تحتوي هذه الخاصية على رابط يشرح المشكلة ببعض التفصيل ، تستطيع الاستفادة منه كمبرمج وربما يستفيد منه المستخدم المتخصص في ال IT لنظامك .

throw exceptions :

خلال تنفيذك للبرنامج يمكن ان يقوم البرنامج بعمل throw لخطأ ما مثل عدم وجود ملف معين . سنتعلم كيفية قراءة هذا الخطأ والتعامل معه ، لكن تظل هناك حالة أخرى ترغب انت فيها بعمل throw للخطأ ، لنفترض انك تقوم بعمل check تتأكد من عدم وجود الملف ومن ثم تقوم بعرض رسالة خطأ في حالة عدم وجود الملف بالشكل التالي مثلاً :

C#:

كود :
if (!System.IO.File.Exists("c:\\ahmed.txt"))
{
Console.WriteLine("there is no file");
}


vb.net:


كود :
If Not System.IO.File.Exists("c:\ahmed.txt") Then
Console.WriteLine("there is no file")
End If


لكنك ربما لم تقم باقتناص خطأ كون الملف للقراءة فقط ، وترغب في صورة قنص اخطاء موحدة ، أو لأي اعتبارات أخرى ترغب في عمل throw للمبرمج مثلاً لو كنت تبرمج كلاس ليتم استخدامه . لأي من هذه الاعتبارات يمكن عمل throw لخطأ بالشكل التالي :

c#:

كود :
if (!System.IO.File.Exists("c:\\ahmed.txt"))
{
throw new Exception("there is no file");
}


vb.net:


كود :
If Not System.IO.File.Exists("c:\ahmed.txt") Then
Throw New Exception("there is no file")
End If


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

نواصل مع الدرس التالي :
catching exceptions :

الآن جاء دور اقتناص الأخطاء ، ابسط طريقة هي باستخدام Try بحيث يخرج البرنامج من البلوك في حالة وجود الخطأ دون ان يتسبب في توقف البرنامج ، بالشكل التالي مثلاً :

C#:


كود :
try
{
x+=100;
console.writeLine("no errror");
}
catch
{
console.writeLine("some error!");
}
VB.net:

Try

كود :
x += 100
console.writeLine("no errror")
Catch
console.writeLine("some error!")
End Try
في حالة وجود خطأ في عملية الجمع السابقة فسيتم مباشرة الانتقال إلى catch ، فيما عدا ذلك سيواصل البرنامج دون المرور عليها ، وفي كل الاحيان لن يتم ايقاف البرنامج .

يمكننا ايضاً عرض تفاصيل عن الخطأ الذي حدث باستخدام الخصائص السابقة :

c#:


كود :
try
{
x += 100;
console.writeLine("no errror");
}
catch (Exception e)
{
Console.WriteLine("Method: {0}", e.TargetSite);
Console.WriteLine("Message: {0}", e.Message);
Console.WriteLine("Source: {0}", e.Source);
}
vb.net:


كود :
Try
x += 100
console.writeLine("no errror")
Catch e As Exception
Console.WriteLine("Method: {0}", e.TargetSite)
Console.WriteLine("Message: {0}", e.Message)
Console.WriteLine("Source: {0}", e.Source)
End Try
لو كنا نعرف بعض الأخطاء التي يمكن ان تحدث ، فيمكننا اختبارها وعرض الرسالة فيما عدا ذلك ، لنفترض المثال التالي في حالة كوننا نعرف أن الخطأ يمكن ان يكون بسبب overflow ، وفيما عدا ذلك سنظهر رسالة بخطأ عام :

C#:

try

كود :
{
x += 100;
console.writeLine("no errror");
}
catch (OverflowException e0)
{
Console.WriteLine("value of x more than up bound");
}
catch (Exception e)
{
Console.WriteLine("Method: {0}", e.TargetSite);
Console.WriteLine("Message: {0}", e.Message);
Console.WriteLine("Source: {0}", e.Source);
}
vb.net:


كود :
Try
x += 100
console.writeLine("no errror")
Catch e0 As OverflowException
Console.WriteLine("value of x more than up bound")
Catch e As Exception
Console.WriteLine("Method: {0}", e.TargetSite)
Console.WriteLine("Message: {0}", e.Message)
Console.WriteLine("Source: {0}", e.Source)
End Try
Finally :

تستخدم للتنفيذ بعد نهاية البلوك try - catch ويتم تنفيذها في حالة وجود خطأ او عدمه ، فمثلاً لو كنا نرغب في طباعة نص ما بغض النظر عن حدوث خطأ في المتغير x من عدمه نكتب الكود التالي :

C#:


كود :
try
{
x += 100;
console.writeLine("no errror");
}
catch (Exception e)
{
Console.WriteLine("Method: {0}", e.TargetSite);
Console.WriteLine("Message: {0}", e.Message);
Console.WriteLine("Source: {0}", e.Source);
}
finally
{
Console.WriteLine("somehing");
}


vb.net:


كود :
Try
x += 100
console.writeLine("no errror")
Catch e As Exception
Console.WriteLine("Method: {0}", e.TargetSite)
Console.WriteLine("Message: {0}", e.Message)
Console.WriteLine("Source: {0}", e.Source)
Finally
Console.WriteLine("somehing")
End Try


break :

للخروج من الاستنثناء في مرحلة ما ، يمكن استخدام break أو Exit Try بالنسبة للفيجوال بيسك .
Target Site :

توفر هذه الخاصية معلومات عديدة حول الكلاس والدالة التي قامت بعمل throw للخطأ ، يمكن الاستفادة منها في عمل Debug لمعرفة مكان حدوث الخطأ .

HelpLink :
تستطيع افادة مستخدم الكلاس أو المستخدم بها ، عن طريق وضع لينك معين يمكنه الاستفادة منه بالشكل التالي مثلاً :

C#:


كود :
[FONT=Tahoma]try[/FONT]
[FONT=Tahoma]{[/FONT]
[FONT=Tahoma]m += 100;[/FONT]
[FONT=Tahoma]Console.WriteLine("no errror");[/FONT]
[FONT=Tahoma]}[/FONT]
[FONT=Tahoma]catch (Exception e)[/FONT]
[FONT=Tahoma]{[/FONT]
[FONT=Tahoma]e.HelpLink = "www.ahmedgamal-space.blogspot.com";[/FONT]
[FONT=Tahoma]}[/FONT]
vb.net:


كود :
[FONT=Tahoma]Try [/FONT]
[FONT=Tahoma]m += 100 [/FONT]

[FONT=Tahoma]Console.WriteLine("no errror") [/FONT]
[FONT=Tahoma]Catch e As Exception [/FONT]

[FONT=Tahoma]e.HelpLink = "[/FONT][url=http://www.ahmedgamal-space.blogspot.com/][FONT=Tahoma]www.ahmedgamal-space.blogspot.com[/FONT][/url][FONT=Tahoma]" [/FONT]
[FONT=Tahoma]End Try [/FONT]
نكتفي بهذا القدر لهذا الدرس ، رغم ان الموضوع يحتوي على الكثير من النقاط ، كيفية بناء خطأ خاص ومستويات الأخطاء وخلافه ، للتوسع في هذا المجال يمكن الرجوع إلى msdn .

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