
Car מתארת מכונית במשחק. הדלק יורד במהלך הנסיעה, ורק המכונית יודעת מתי הוא מגיע לרמה קריטית.delegate void FuelHandler(double fuelLeft);. שם כזה מסתיים בדרך כלל ב-Handler.public event FuelHandler NoFuel; יוצרת את האירוע. המילה event מגבילה את השימוש במשתנה.NoFuel(fuel). לפני כן בודקים שיש נרשמים, כי אחרת נוצרת NullReferenceException.showFuel(double fuelLeft) שמציגה הודעה למסך.car.NoFuel += showFuel;. השימוש ב-+= מוסיף נרשם, ולא מחליף את הנרשמים הקיימים.event אי אפשר לבצע = מבחוץ, כדי שמשתמש אחד לא ימחק את הנרשמים של אחרים. מותר רק += ו--=.NoOil לא מעביר ערך, והפונקציה שמאזינה לו מציגה רק הודעה.הטקסט המלא של הדקות הראשונות בהרצאה «אירועים - Events - חלק 1» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
אנחנו מגיעים לנושא מאוד מאוד חשוב וגם מאוד בסיסי בעולם פיתוח התוכנה, שכמובן קשור לעולם ה-object oriented, והנושא הזה נקרא אירועים באנגלית events. דבר ראשון, בואו נגדיר מה זה אירוע.
אירוע הוא מקרה מסוים שהתרחש במהלך פעילות פנימית של מחלקה, כלומר במהלך פונקציה מסוימת של מחלקה, והמחלקה מעוניינת לדווח על האירוע הזה או להודיע שהאירוע קרה או שהמקרה הזה התרחש למי שמשתמש במחלקה.
זאת אומרת, אנחנו יודעים שבעולם ה-object-oriented ישנם שני מתכנתים. זה ה-viewpoint הבסיסי שלנו. מתכנת א' זה המתכנת שבונה מחלקה.
מתכנת ב' זה המתכנת שמשתמש במחלקה. במהלך פעילות המחלקה, של איזושהי פונקציה מסוימת שמתרחשת לאורך זמן, פתאום קרה משהו ומי שבונה את המחלקה מעוניין להודיע על זה למי שמשתמש במחלקה.
אבל כאן אנחנו נתקלים באיזושהי בעיה, מפני שאם אנחנו כותבים איזושהי מחלקה אנחנו לא אמורים לדעת אף פעם מי זה שמשתמש במחלקה שלנו. אנחנו לא אמורים להכיר אותו, אנחנו לא אמורים להכיר פונקציות באזור שלו, ולכן פתאום קיימת פה איזושהי סיטואציה של אם אנחנו לא מכירים אותו איך אנחנו בדיוק הולכים להודיע
לו משהו הרי אנחנו צריכים לקרוא לאיזושהי פונקציה שקיימת באזור שלו של מי שמשתמש איתנו אנחנו לא מכירים אותו לא מכירים את האזור שלו לא מכירים שם שום מחלקות ולא מכירים שם שום פונקציות ועדיין אנחנו רוצים לקרוא לאיזושהי פונקציה שקיימת אצלו ובזה שאנחנו קוראים לה להודיע שמשהו קרה אצלנו
בואו ניקח דוגמה ונבנה את זה לפי הסדר דבר ראשון אנחנו הולכים לבנות איזושהי מחלקה שמתארת מכונית, בואו נניח מכונית של משחק מכוניות.
אז נצרף פה איזושהי מחלקה ונקרא לה Car. ובואו נניח שהתוכנית שלנו מתעסקת במשחק מכוניות ויש לנו פה מחלקה שמתארת מכונית וכמובן יש לנו פה פונקציה שמאפשרת לנסוע.
והפונקציה הזאת פשוט ברגע שקוראים לה גורמת למכונית להתחיל לנסוע. עכשיו בואו ניקח דוגמה שאנחנו נוסעים ונוסעים ונוסעים ואנחנו בעצם המחלקה car אחראית על כל מה שקשור למכונית.
תחשבו על מכונית אמיתית שקיימת בעולם. פתאום אין דלק או שהגענו למצב שבו הדלק מגיע לנקודה קריטית והולך להיגמר. אז אם אתם באמת בעולם הפיזיקלי נוהגים במכונית, מי הראשון שיודע שנגמר הדלק או שהדלק הולך להיגמר?
האם אתם יודעים את זה ראשונים או האם המכונית יודעת את זה ובגלל שהיא מצליחה לגלות את זה על ידי איזשהו חיישן היא מודיעה לכם ורק אז אתם יודעים את זה.
אז כמובן שאם היא לא הייתה מודיעה לכם לא היה לכם מושג שהולך להיגמר הדלק. מי שאחראי על הדלק זה המכונית והיא יודעת שהולך להיגמר לה הדלק וברגע שזה קורה היא פשוט מודיעה לכם על ידי איזושהי מנורה שכנראה נדלקת.
בדיוק אותו הדבר אנחנו רואים שאנחנו צריכים לבצע כאן. המכונית עצמה יודעת בדיוק כמה דלק יש לה. בוא נניח שהדלק זה איזשהו משתנה, ניקח איזשהו דאבל, נקרא לו פיול ונתחיל לנהוג עם 10 ליטר או 10 ליטרים.
ועכשיו אנחנו מדמים מצב שבו אנחנו נוהגים במכונית. אז בוא נניח שאנחנו מבצעים איזושהי נהיגה בפיספור דרייבינג, נבצע הדמיה כאילו שזה לוקח לנו נניח שנייה, זה יהיה delay של שנייה, בואו אפילו נעשה את זה פשוט.
נניח אנחנו נוהגים ובמשך 10 שניות אנחנו בעצם מרצים את הנהיגה הזאת וכל שנייה הפיול פוחת בבוא נניח ליטר אחד. אנחנו נוהגים באיזה ג'יפ לנד רובר או משהו כזה, כל שנייה הולך ליטר.
עכשיו ברגע שאנחנו מגיעים למצב קריטי של בוא נניח שלושה ליטר ומטה, אנחנו יודעים שיש פה איזושהי בעיה ואנחנו אנחנו רוצים לדווח שמשהו קרה, או ליטר אחד או שניים, לא משנה כמה שאנחנו נחליט.
מי שמשתמש במחלקה קורא לפונקציית דרייב ואומר, טוב, אני רוצה להתחיל לנסוע. במהלך הנסיעה, שלוקחת הרבה זמן מן הסתם, פתאום משהו קורה.
מה קורה? מתחיל להיגמר הדלק, או שהדלק הגיע לאיזשהו מצב קריטי. כאן אנחנו רוצים לבצע בדיקה, במידה והפיול קטן או שווה ל-1, בדיוק במצב בנקודה הזאת, אנחנו רוצים לדווח שאין מספיק דלק.
אבל למי אנחנו רוצים לדווח? אנחנו בדיוק בנקודה הזאת רוצים לקרוא לאיזושהי פונקציה שקיימת מחוץ למחלקה, באותו אזור שמשתמש במחלקה.
וכאן אנחנו צריכים להבין שאנחנו נמצאים בעולם של Object Oriented. זה עולם של מוכוון עצמים. וזה אומר שאת המחלקה אנחנו כותבים עכשיו, ויכול להיות שבעוד שנה מישהו הולך להשתמש בה.
אין לנו מושג מי זה, איזה מחלקה הזאת שהולכת להשתמש בנו ושקיימת אצלו ואיזה פונקציות יש בה. אז איך אנחנו מצליחים בכל זאת לקרוא לאיזושהי פונקציה שקיימת באזור אחר שמשתמש בנו ואנחנו לא מכירים את האזור הזה?
התשובה לשאלה הזאת חייבת לבוא מתחום הדלגייטס. אנחנו למדנו בסרטון הקודם על דלגייטס ואנחנו ראינו שדלגייט בעצם זה מצביע לפונקציה. מה אם הייתי אומר לכם שאנחנו יכולים שיהיה לנו איזשהו משתנה שיוכל להחזיק את הכתובת של הפונקציה שלו?
אם הוא רוצה לקבל את הדיווחים, כל מה שהוא צריך לעשות זה להכניס לתוך המשתנה שלנו את הכתובת של הפונקציה שלו. אם הוא הכניס את הכתובת של הפונקציה, יש לנו את הכתובת שלה ואנחנו מסוגלים לקרוא לה.
וזה בעצם כל הפתרון בנוגע לצורך לדווח שמשהו קרה. הקונספט של אירועים ודיווח כאשר אנחנו בתוך המחלקה שלנו יודעים שמשהו קרה ואנחנו מעוניינים לדווח את זה לעולם החיצוני.
אז איך אנחנו עכשיו בונים את כל המנגנון הזה? אז למעשה כל המנגנון של אירועים בנוי משני חלקים. חלק ראשון ומי שכותב את כל המחלקה והוא מעוניין לדווח על אותו דבר שקרה. במקרה שלנו מה שקרה הוא שהדלק הולך להיגמר ואנחנו אנחנו רוצים להגיד לו את זה, תקשיב, או שתיכנס
לתחנת דלק, או שאתה תפסיד את המשחק, או שהמכונית שלך תעצור באמצע. הוא יחליט מה הוא רוצה לעשות עם זה, אנחנו, רק התפקיד שלנו מתוך המחלקה זה לדווח לו על האירוע שכרגע קרה.
אז זה החלק הראשון. החלק השני זה מי שמשתמש עם המחלקה וצריך עכשיו לתת לנו כתובת של פונקציה ולקבל את הדיווח וכמובן לעשות איתו משהו.
אז איך אנחנו בונים את זה? מי שכותב את המחלקה מחליט בדיוק מהו האירוע ומה ברצונו לדווח ועל איזה חתימה של פונקציה הוא צריך לקרוא והוא עושה את זה על ידי הכנת דלגייט.
עכשיו אנחנו צריכים לחשוב רגע מה בדיוק אנחנו הולכים לדווח אנחנו הולכים לדווח שאין מספיק דלק אז כדאי לנו אולי לדווח גם כמה דלק נשאר לנו אם אני רוצה לדווח כמה דלק נשאר והדלגייט הוא דאבל אז אולי כדאי לשלוח משתנה שהוא דאבל.
אוקיי, אז בואו נבנה דלגייט שיהיה מסוגל להצביע על פונקציות שמקבלות דאבל כי אנחנו רוצים לקרוא לפונקציה קבלות ומחזירות ווייד. נקרא לדלגייט הזה פיול הנדלר.
נהוג שדלגייטים שקשורים לאירועים יסתיימו במילה הנדלר. ואנחנו הולכים לשלוח דאבל פיול לפט. והנה בנינו דלגייט, זה הצעד הראשון בבנייה של אירוע.
הצעד השני יהיה לבנות משתנה מהדלגייט. משתנה של אירוע זה תמיד משתנה ברמת המחלקה, ברוב המקרים היא תהיה לו הרשאת גישה public. אנחנו מגדירים את המילה Event ואת השם של הדלגייט.
ועכשיו אנחנו ממציאים שם של משתנה. לדוגמה NoFuel. למה אנחנו צריכים את המילה Event אנחנו עוד מעט נראה, ומה היא בדיוק נותנת לנו. אוקיי, אז יש לנו פה את המשתנה וזה יהיה צעד מספר 2. זה בעצם האיבנט, וזה איזשהו משתנה מטיפוס הדלגייט.
צעד מספר שלוש יהיה פשוט לדווח שמשהו קרה. במידה ואין לנו מספיק דלק, אנחנו עכשיו רוצים להשתמש ב-NoFuel בכדי לדווח את הדלק שנשאר לנו. אוקיי, אז אנחנו רואים כרגע שיש לנו בעצם את הדיווח עצמו.
בואו נניח שנדפיס כאן End Off, נרשום End Driving. יש לנו פה בעצם שלושה צעדים שביצענו כאשר בנינו את המחלקה. דבר ראשון, בנינו איזשהו דלגייט שמסוגל להצביע על פונקציות שמקבלות דאבל ומחזירות ווייד.
דבר שני, בנינו איזשהו משתנה מהדלגייט הזה עם המילה השמורה Event. דבר שלישי, כאשר אנחנו יודעים שמשהו קרה, כל מה שאנחנו רוצים לעשות זה לדווח.
זה יהיה פר 3. זה נקרא Raising the Event. עכשיו אנחנו הולכים לאזור שמשתמש עם המחלקה. בואו נשים אותה פה בצד. מה צריך לעשות האזור שמשתמש עם המחלקה? אזור שמשתמש עם המחלקה עושה מספר צעדים.
דבר ראשון יוצר אובייקט מהמחלקה car c=new car. דבר שני הוא חייב ללכת וליצור לעצמו איזושהי פונקציה. אנחנו חייבים ליצור את הפונקציה באותה חתימה בדיוק של הדלגייט.
ויש לנו פה static void show fuel double fuel left. נדפיס כאן not enough fuel fuel left. דבר הבא שאנחנו צריכים לעשות, יש לנו את הפונקציה שהמחלקה לא מכירה.
אנחנו רוצים לתת את הכתובת של הפונקציה ל-delegate שבנינו בתוך המחלקה, או ל-event יותר נכון. זה יהיה registering the event.
c.no-fuel אנחנו רוצים לתת את הערך. אם אנחנו מבצעים את הדבר הזה, אנחנו הולכים לחטוף איזושהי שגיאת קומפילציה. וכאן אנחנו רואים שיש פה איזושהי בעיה להכניס את הכתובת של הפונקציה לתוך משתנה שמוגדר עם event.
אם אנחנו נוריד את המילה event אנחנו רואים שהבעיה נפתרה. כלומר אין לנו פה שגיאת קומפילציה כרגע ומותר לנו לקחת פונקציה ולהכניס אותה לתוך משתנה מסוג delegate.
ברגע שאנחנו מוסיפים את המילה event אז פתאום אנחנו לא מצליחים לבצע שווה. והסיבה היא שהמערכת לא מסכימה שאנחנו נכניס איזושהי פונקציה לתוך משתנה event אם שווה, ויכול להיות שבאזורים