194. add remove event accessors

פעם קודמת הכרנו קצת את המושג Event.

ראינו שזה בעצם Delegate שהקומפיילר מגביל את השימוש שלו מחוץ למחלקה בה הוא נמצא, כך שיהיה אפשר רק להירשם אליו או להסיר רישום ממנו.

אמרתי גם שזה מזכיר קצת את ההכמסה שמבצע Property.

אך אפשר לומר שProperty נותן יותר גמישות, מאחר ואנחנו יכולים לכתוב איזה קוד שאנחנו רוצים בaccessorים שלו (הgetter או הsetter), ואילו Event זו מגביל לשימוש בadd וremove, אבל בלי כתיבת קוד בגישות אלה.

אלא שקיימת אפשרות גם לכתוב לוגיקה בהוספה והסרה של eventים.

זה מתבצע באמצעות הכתיבה הבאה:

במקום כך:

1
2
3
4
public class EventRaiser
{
public event EventHandler Raised;
}

נכתוב כך:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class EventRaiser
{
private EventHandler mRaised;
public event EventHandler Raised
{
add
{
mRaised += value;
}
remove
{
mRaised -= value;
}
}
}

זו כתיבה שמאוד דומה לכתיבה של Properties. כאשר תתבצע הרשמה או הסרת רישום לאירוע, יקראו בהתאמה הAccessorים של הadd או הremove.

כך שאם אנחנו רוצים לעשות לוגיקה משלנו, אנחנו יכולים לעשות אותה בAccessorים אלה:

לדוגמה,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private int mNumOfSubscriptions;
public event EventHandler Raised
{
add
{
mRaised += value;
mNumOfSubscriptions++;
}
remove
{
mRaised -= value;
// TODO: Check if the handler was already registered
// TODO: and decrease the number of subscriptions.
mNumOfSubscriptions--;
}
}

למעשה, פונקציות אלה נוצרות מאחורי הקלעים גם אם השתמשנו בSyntax הראשון:

1
2
3
4
public class EventRaiser
{
public event EventHandler Raised;
}

מתקמפל מאחורי הקלעים למשהו כזה:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class EventRaiser
{
private EventHandler mRaised;
public event EventHandler Raised
{
add
{
this.mRaised += value;
}
remove
{
this.mRaised -= value;
}
}
}

בדומה לProperties שמתמקפלים לפונקציות מהצורה get_Property או set_Property, Eventים מתמקפלים לפונקציות מהצורה add_Event וremove_Event.

בשונה מProperties, בEventים אין לנו את החופש לבחור האם לממש רק את אחד הAccessorים (add או remove), אלא אנחנו מוכרחים לממש את שניהם, מאחר ומי שמשתמש במחלקה שלנו מבחוץ רואה שאנחנו חושפים Event ולכן מבחינתו אנחנו חושפים את שתי האפשרויות.

בד"כ לא נרצה לכתוב מימוש משלנו בתוך הAccessorים אלא במקרים מיוחדים, כמו שחשוב לנו שרישום יהיה Thread-safe, או לחלופין כאשר נרצה לוגיקה משלנו (למשל כשאנחנו חושפים Event של מישהו אחר)

המשך יום מלא רישומים והסרות טוב

שתף