בדוק כיצד ליצור ולהשליך חריגות ב- C#
- 16 דקות
.NET מספק הירארכיה של מחלקות חריגות הנגזרות מחלקת System.Exception הבסיס. יישומי C# יכולים ליצור ולהוות חריגות מכל סוג חריגה. מפתחים יכולים גם להתאים אישית אובייקטי חריגה עם מידע ספציפי ליישום על-ידי הקצאת ערכי מאפיינים.
הערה
מודול זה מתמקד ביצירה וב התרה של חריגות, ובהתאמה אישית של אובייקטי חריגה. יצירת מחלקות חריגה מותאמות אישית נמצאת מחוץ לטווח של מודול זה.
יצירת אובייקט חריג
יצירת חריגים מתוך הקוד שלך והודעות התראת חריגות היא היבט חשוב של תיכנות C#. היכולת ליצור חריגה בתגובה למצב, לבעיה או לשגיאה ספציפיים מסייעת לך להבטיח את יציבות היישום.
סוג החריגה שאתה יוצר תלוי בבעיית הקידוד, והוא אמור להתאים למטרה המיועדת של החריגה בהקדם האפשרי.
לדוגמה, נניח שאתה יוצר שיטה בשם GraphData שמבצעת ניתוח נתונים. פעולת השירות מקבלת מערך נתונים פרמטר קלט. פעולת השירות מצפה כי נתוני הקלט יהיו בטווח מסוים. אם פעולת השירות מקבלת נתונים מחוץ לטווח הצפוי, היא יוצרת ומסירה חריגה מסוג ArgumentException. החריגה תטופלי במקום כלשהו במורד ערימת הקריאות על-ידי הקוד האחראי לאספקת הנתונים.
להלן כמה סוגי חריגים נפוצים שבהם אתה עשוי להשתמש בעת יצירת חריגה:
-
ArgumentExceptionלחלופיןArgumentNullException: השתמש בסוגי חריגים אלה כאשר מתבצעת קריאה לפעולת שירות או לבנאי עם ערך ארגומנט או הפניה Null לא חוקיים. -
InvalidOperationException: השתמש בסוג חריג זה כאשר תנאי ההפעלה של פעולת שירות אינם תומכים בהשלמה מוצלחת של קריאה לשיטה מסוימת. -
NotSupportedException: השתמש בסוג חריג זה כאשר פעולה או תכונה אינן נתמכות. -
IOException: השתמש בסוג חריג זה כאשר פעולת קלט/פלט נכשלת. -
FormatException: השתמש בסוג חריג זה כאשר התבנית של מחרוזת או נתונים שגויה.
מילת new המפתח משמשת ליצירת מופע של חריגה. לדוגמה, באפשרותך ליצור מופע של סוג החריגה ArgumentException באופן הבא:
ArgumentException invalidArgumentException = new ArgumentException();
קביעת תצורה של חריגות מותאמות אישית והקצאתן עבורן
התהליך של התריעה על אובייקט חריג כולל יצירת מופע של מחלקה הנגזרת על-ידי חריגה, קביעת תצורה של מאפיינים של החריגה ולאחר throw מכן התריעה על האובייקט באמצעות מילת המפתח.
לעתים קרובות כדאי להתאים אישית חריגה עם מידע הקשרי לפני שהוא התריעה. באפשרותך לספק מידע ספציפי ליישום בתוך אובייקט חריג על-ידי קביעת התצורה של המאפיינים שלו. לדוגמה, הקוד הבא יוצר אובייקט חריג בשם עם invalidArgumentException מאפיין מותאם Message אישית, ולאחר מכן מתרחשת החריגה:
ArgumentException invalidArgumentException = new ArgumentException("ArgumentException: The 'GraphData' method received data outside the expected range.");
throw invalidArgumentException;
הערה
המאפיין Message של חריגה מוגדר לקריאה בלבד. לכן, יש להגדיר Message מאפיין מותאם אישית בעת יצירת מופעים של האובייקט.
בעת התאמה אישית של אובייקט חריג, חשוב לספק הודעות שגיאה ברורות המתארות את הבעיה וכיצד לפתור אותה. באפשרותך גם לכלול מידע נוסף כגון מעקבי מחסנית וקודים של שגיאות כדי לעזור למשתמשים לפתור את הבעיה.
ניתן גם ליצור אובייקט חריג ישירות בתוך throw משפט. לדוגמה:
throw new FormatException("FormatException: Calculations in process XYZ have been cancelled due to invalid data format.");
כמה שיקולים שעליך לזכור בעת התריעה על חריגה כוללים:
- המאפיין
Messageאמור להסביר את הסיבה לחריגה. עם זאת, אין להוסיף לטקסט ההודעה מידע רגיש או שמייצג חשש אבטחה. - המאפיין
StackTraceמשמש לעתים קרובות למעקב אחר מקור החריגה. מאפיין מחרוזת זה מכיל את שם פעולות השירות במחסנית הקריאות הנוכחית, יחד עם שם הקובץ ומספר השורה בכל פעולת שירות המשויכת לחריגה. אובייקטStackTraceנוצר באופן אוטומטי על-ידי זמן הריצה של השפה הנפוצה (CLR) מנקודתthrowהמשפט. יש לציין חריגים מהנקודה שבה המעקב אחר המחסנית אמור להתחיל.
מתי להפעיל חריגה
שיטות אמורות להציג חריגה בכל פעם שהן לא מצליחות להשלים את המטרה המיועדת שלהן. החריגה שנזרקה אמורה להיות מבוססת על החריגה הספציפית ביותר הזמינה המתאימה לתנאי השגיאה.
שקול תרחיש שבו מפתח עובד על יישום המיישם תהליך עסקי. התהליך העסקי תלוי בקלט המשתמש. אם הקלט אינו תואם לסוג הנתונים הצפוי, השיטה המיישמת את התהליך העסקי יוצרת ומשליכת חריגה. ניתן לקבוע את תצורת אובייקט החריגה עם מידע ספציפי ליישום ערכי המאפיינים. דוגמת הקוד הבאה מדגימה את התרחיש:
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach (string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1") && (ex is FormatException))
{
Console.WriteLine(ex.Message);
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
// completes required calculations based on userValue
// ...
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
}
}
בדוגמה זו של קוד, המשפטים ברמה העליונה קוראים לפעולת השירות, ועוברים מערך מחרוזות המכיל ערכים שהוזנו על-ידי BusinessProcess1 המשתמש. פעולת BusinessProcess1 השירות מצפה לערכים של קלט משתמש שניתן להמיר למספר שלם. כאשר פעולת השירות נתקלת בנתונים עם תבנית לא חוקית, היא יוצרת מופע של FormatException סוג החריגה באמצעות מאפיין מותאם Message אישית. לאחר מכן, פעולת השירות היא היוצא מן הכלל. החריגה נתפסת במשפטים ברמה העליונה אובייקט בשם ex. מאפייני האובייקט נבדקים ex לפני הצגת הודעת החריגה למשתמש. תחילה, הקוד בוחן את המאפיין StackTrace כדי לראות אם הוא מכיל "BusinessProcess1". שנית, אובייקט החריגה ex מאומת להיות מסוג FormatException.
חריגות התרה מחדש
בנוסף להצגת הודעה על חריגה חדשה, throw ניתן להשתמש בהתהוות מחדש בחריגה מתוך catch בלוק קוד. במקרה זה, אינו throw משתמש באופרנד חריג.
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// re-throw the original exception object for further handling down the call stack
throw;
}
בעת התרה מחדש של חריגה, נעשה שימוש באובייקט החריגה המקורי, כך שלא תאבד מידע אודות החריגה. אם ברצונך ליצור אובייקט חריג חדש אשר גולש את החריגה המקורית, באפשרותך להעביר את החריגה המקורית כארגומנט לבנאי של אובייקט חריג חדש. לדוגמה:
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred", ex);
}
עבור תרחיש היישום "BusinessProcess1", שקול את העדכונים הבאים:
- פעולת
BusinessProcess1השירות עודכנה כדי לכלול פרטים נוספים.BusinessProcess1כעת נתקל בשתי בעיות ועלי ליצור חריגים עבור כל בעיה. - המשפטים ברמה העליונה עודכנו. משפטים ברמה העליונה קוראים כעת לפעולת
OperatingProcedure1השירות.OperatingProcedure1שיחותBusinessProcess1בתוךtryבלוק קוד. - פעולת
OperatingProcedure1השירות יכולה לטפל באחד מסוגי החריגים ולטפל באופן חלקי באחד מסוגי החריגים. לאחר עיבוד החריגה שנטפלה חלקית, ישOperatingProcedure1להפעיל מחדש את החריגה המקורית.
דוגמת הקוד הבאה מדגימה את התרחיש המעודכן:
try
{
OperatingProcedure1();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Exiting application.");
}
static void OperatingProcedure1()
{
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach(string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1"))
{
if (ex is FormatException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Corrective action taken in OperatingProcedure1");
}
else if (ex is DivideByZeroException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Partial correction in OperatingProcedure1 - further action required");
// re-throw the original exception
throw;
}
else
{
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred - ", ex);
}
}
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
checked
{
int calculatedValue = 4 / valueEntered;
}
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
catch (DivideByZeroException)
{
DivideByZeroException unexpectedDivideByZeroException = new DivideByZeroException("DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero");
throw unexpectedDivideByZeroException;
}
}
}
הקוד לדוגמה המעודכן מפיק את הפלט הבא:
FormatException: User input values in 'BusinessProcess1' must be valid integers
Corrective action taken in OperatingProcedure1
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Partial correction in OperatingProcedure1 - further action required
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Exiting application.
דברים שיש להימנע בהם בעת התריעה על חריגים
הרשימה הבאה מזהה שיטות עבודה להימנעות מהודעות חריגות:
- אל תשתמש בחריגים כדי לשנות את זרימת התוכנית כחלק מביצוע רגיל. השתמש בחריגים כדי לדווח על תנאי שגיאה ולטפל בהם.
- אין להחזיר חריגים כערך החזרה או פרמטר במקום להיות מוחזרים.
- אל תזרוק
System.Exceptionאת ,System.SystemException,System.NullReferenceException, אוSystem.IndexOutOfRangeExceptionבמכוון מתוך קוד המקור שלך. - אל תיצור חריגים שניתן לזרוק במצב איתור באגים, אך לא במצב הפצה. כדי לזהות שגיאות זמן ריצה במהלך שלב הפיתוח, השתמש במקום
Debug.Assertזאת.
הערה
השיטה Debug.Assert היא כלי ללכידת שגיאות לוגיות במהלך הפיתוח. כברירת מחדל, פעולת השירות Debug.Assert פועלת רק בגירסאות Build לאיתור באגים. באפשרותך להשתמש בהפעלות Debug.Assert איתור באגים כדי לבדוק אם יש תנאי שמעולם לא אמור להתרחש. פעולת השירות מקבלת שני פרמטרים: תנאי בוליאני לצורך בדיקה, והודעת מחרוזת אופציונלית להצגה אם התנאי הוא false.
Debug.Assert אין להשתמש בו במקום התריעה על חריגה, שהיא דרך לטיפול במצבים יוצאי דופן במהלך ביצוע רגיל של הקוד שלך. עליך להשתמש כדי Debug.Assert לאתר שגיאות שמעולם לא אמורות להתרחש, ולהשתמש בחריגים כדי לטפל בשגיאות שעלולות להתרחש במהלך ביצוע רגיל של התוכנית שלך.
סיכום
להלן כמה דברים חשובים שיש לזכור ביחידה זו:
- בעת יצירה ו התרה של חריגה, סוג החריגה חייב להתאים למטרה המיועדת של החריגה בהקדם האפשרי.
- לחריגה
throw, אתה יוצר מופע של מחלקה שנגזרה על-ידי חריגה, מגדיר את המאפיינים שלה ולאחר מכן משתמש במילתthrowהמפתח. - בעת יצירת אובייקט חריג, חשוב לספק הודעות שגיאה ברורות ומידע נוסף כדי לעזור למשתמשים לפתור את הבעיה.
בדוק את הידע שלך
משוב
האם עמוד זה היה מועיל?
לא
זקוק לעזרה בנושא זה?
רוצה לנסות להשתמש ב'שאל את Learn' כדי להבהיר או להדריך אותך בנושא זה?