352. Continuing with interception

בהמשך לפעם הקודמת, הפעם ננסה להגדיר באופן יותר מדויק מהי הפעולה של Interception.

נאמר שIntercept של פונקציה הוא קריאה לפונקציה אחרת, כך שהפונקציה האחרת מבצעת את הפעולה.

בנוסף, לפונקציה האחרת יש אופציה לבצע את הקריאה המקורית שהייתה לפונקציה.

כמו בProxy, נגדיר חתימה לפונקציה שאליה נכנס במקום הפונקציה שקראנו אליה:

הפונקציה תקבל איזשהו אובייקט עם המידע הבא:

כל המידע שקיבלנו בProxy (מועתק מטיפ מספר 345):

  • המתודה שהופעלה – אבל אנחנו רוצים יותר מאת השם, אלא את הOverload המתאים שנקרא. כלומר, כנראה את הMethodInfo של המתודה המתאימה שהופעלה.
  • הפרמטרים שאיתם נקראה המתודה – מדובר במבנה המכיל את הפרמטרים שנשלחו למתודה. ניתן לשלוח את זה בתור מיפוי כלשהו, או בתור מערך שאליו ניגש לפי הסדר של הפרמטרים בMethodInfo כדי למצוא פרמטר ספציפי.
  • בנוסף, היינו מצפים לקבל את הפרמטרים הגנריים של המתודה, אם יש כאלה. אותם אנחנו יכולים לקבל גם בתוך הMethodInfo בהנחה שקראו לMakeGenericType.

בנוסף למידע הזה, נרצה לקבל את האובייקט שהופעלה עליו הפונקציה. (המתודה אליה ננותב, לאו דווקא תהיה שייכת לאובייקט, לכן לא נוכל להשתמש בthis)

בנוסף, היינו מצפים ליכולות הבאות שהיו לנו בProxy (מועתק מטיפ מספר 345):

  • לקבוע את ערך ההחזר של המתודה שהופעלה
  • לשנות את הפרמטרים שהם ref או out
  • לזרוק Exception ביציאה מהפונקציה

בנוסף ליכולות אלה, נרצה אופציה להפעיל את הקריאה של הפונקציה המקורית, עם אופציה לשנות את הפרמטרים.

הדבר מאוד דומה לProxy, רק שיש לנו אופציה להמשיך את הקריאה המקורית.


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

במקום זאת, היה אולי יותר טוב לכתוב כך:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public int GetAvailableBudget(string id)
{
MethodCallInfo callInfo =
new MethodCallInfo("GetAvailableBudget",
message => InnerGetAvailableBudget
((string) message.Arguments[0]))
{
{"id", id},
};
Route(callInfo);
return (int)callInfo.ReturnValue;
}
private int InnerGetAvailableBudget(string id)
{
// Implementation
}
private void Route(MethodCallInfo methodCallInfo)
{
Console.WriteLine("Called {0} with arguments:");
foreach (KeyValuePair<string, object> argument in methodCallInfo)
{
Console.WriteLine("\t{0} : {1}",
argument.Key,
argument.Value);
}
methodCallInfo.Proceed();
Console.WriteLine("Returned from {0} with value {1}.",
methodCallInfo.Name,
methodCallInfo.ReturnValue);
}

שימו לב:

הפונקציה קוראת לפונקציה Route עם הפרמטרים שקיבלה ומחזירה משם את ערך ההחזר.

זה מאוד דומה למה שקורה בProxy, רק שכאן הפונקציה שולחת גם Delegate המאפשר לבצע את הקריאה לפונקציה המקורית.

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

שימו לב שזה מאוד דומה לProxy, רק שיש לנו אופציה להמשיך את הקריאה המקורית.

כמובן, לא נרצה שהקוד שלנו יראה כך. בהמשך נדבר על דרכים אחרות לממש Interception ושימושים של Interception (לאו דווקא בסדר הזה).

המשך יום מיורט לטובה.

שתף