354. Logging interception

נתחיל כעת לראות שימושים נחמדים בInterception.

השימושים שנראה הם בעיקר על מנת לנקות את הקוד שלנו מההתעסקות ב”מסביב” ולהשאיר בו את הלוגיקה שלו. (נדבר על הקונספט הזה עוד בהמשך, מה שנקרא גם Aspect Oriented Programming)

השימוש הראשון שנראה ואולי המתבקש ביותר הוא שימוש בInterception בשביל Logging:

כמו כל מערכת טובה, אנחנו מעוניינים לכתוב לLog את הפעולות הבאות:

  1. כאשר מתבצעת כניסה לפונקציה
  2. כאשר מתבצעת יציאה מפונקציה עם ערך ההחזר
  3. כאשר עף Exception

אם היינו רוצים לעשות את זה על כל פונקציה, כל פונקציה שלנו הייתה נראית כך:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public int MyMethod(int id, string name)
{
mLog.DebugFormat("Entering MyMethod, with parameters id:{0}, name:{1}",
id, name);
try
{
int result;
// My Method content
mLog.DebugFormat("Exiting MyMethod with return value: {0}", result);
return result;
}
catch (Exception ex)
{
mLog.Error("An error occured on MyMethod", ex);
throw;
}
}

שימו לב שהמתודה שלנו התנפחה ב7 שורות בערך מבלי שבכלל כתבנו את הלוגיקה שלה.

Interception נותן לנו פתרון יותר אלגנטי:

ניצור מתודה שאליה יכנסו כל הקריאות שלנו:

1
2
3
4
public void Route(MethodCallInfo call)
{
call.Proceed();
}

ואז נשנה אותה כך שתבצע את הפעולות שדיברנו עליהן:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void Route(MethodCallInfo call)
{
mLog.DebugFormat("Entering {0}, with parameters {1}",
call.Method,
GetParameters(call));
try
{
call.Proceed();
mLog.DebugFormat("Exiting {0} with return value: {1}",
call.Method,
call.ReturnValue);
}
catch (Exception ex)
{
mLog.Error("An error occured on " + call.Method, ex);
throw;
}
}

מטורף! כעת רק צריך איכשהו "להתקין" את הInterception הזה על המחלקות שלנו וקיבלנו הרבה לוגים בחינם!

ראינו בעבר מספר דרכים לביצוע Intercept: שינוי קוד ועטיפת קוד בDesign Pattern של Decorator.

נראה בהמשך מספר דרכים יותר נוחות לביצוע Intercept, אבל מה שחשוב כרגע להבין את הקונספט ואת הכוח.

המשך יום עם לוגים טוב!

הערה: פונקציית עזר ששומשה בטיפ:

1
2
3
4
5
6
private static string GetParameters(MethodCallInfo call)
{
return string.Join
(",",
call.Method.GetParameters().Select(x => x.Name + ":" + call.Arguments[x.Position]));
}
שתף