המרה כלפי מעלה והמרה כלפי מטה
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C# של Coddy. שיעור 29 מתוך 70.
כשעובדים עם היררכיות של ירושה, לעיתים קרובות צריך להמיר בין טיפוסי בסיס לטיפוסים נגזרים. המרה כלפי מעלה ממירה טיפוס נגזר לטיפוס הבסיס שלו, ואילו המרה כלפי מטה עושה את ההפך.
המרה למחלקת בסיס מתבצעת באופן משתמע והיא תמיד בטוחה, כי מובטח שלמחלקה יורשת יש את כל מה שיש למחלקת הבסיס:
Dog myDog = new Dog();
Animal animal = myDog; // המרה לטיפוס־על - מתבצעת במובלע, תמיד עובדתהמרה כלפי מטה דורשת המרה מפורשת, ועלולה להיכשל בזמן ריצה אם האובייקט אינו באמת מהסוג שאליו ממירים אותו:
Animal animal = new Dog();
Dog dog = (Dog)animal; // המרה מטה - פועלת כי זה באמת Dog
Animal cat = new Cat();
Dog wrong = (Dog)cat; // זורק InvalidCastException!כדי לבצע המרה כלפי מטה בבטחה, השתמשו במילת המפתח is כדי לבדוק קודם את הטיפוס, או השתמשו ב־as, שמחזירה null במקום לזרוק חריגה:
if (animal is Dog d)
{
d.Bark(); // בטוח - d זמין רק אם הבדיקה מצליחה
}
Dog maybeDog = animal as Dog;
if (maybeDog != null)
{
maybeDog.Bark();
}גישת התאמת התבניות is עדיפה ב־C# מודרני, משום שהיא משלבת את בדיקת הטיפוס וההמרה לצעד אחד, וכך הקוד שלך בטוח ונקי יותר.
אתגר
קלבואו נבנה מערכת לבדיקת כלי רכב שמדגימה כיצד המרה כלפי מעלה והמרה כלפי מטה מאפשרות לעבוד בגמישות עם אובייקטים בהיררכיית ירושה. תיצרו סוגים שונים של כלי רכב ותכתבו קוד שמזהה בבטחה סוגים מסוימים של כלי רכב ומבצע איתם פעולות.
תארגנו את הקוד שלכם בארבעה קבצים:
Vehicle.cs: הגדירו מחלקת בסיסVehicleבמרחב השמותInspection. לכל כלי רכב יש מאפייןLicensePlate(מחרוזת) שמוגדר דרך בנאי. כללו מתודה בשםGetBasicInfo()שמחזירה"Vehicle: {LicensePlate}".Car.cs: הגדירו מחלקהCarבמרחב השמותInspectionשיורשת מ-Vehicle. למכוניות יש מאפיין נוסף,NumberOfDoors(מספר שלם). הבנאי מקבל גם את מספר לוחית הרישוי וגם את מספר הדלתות. הוסיפו מתודה בשםHonk()שמחזירה"{LicensePlate} honks: Beep beep!".Motorcycle.cs: הגדירו מחלקהMotorcycleבמרחב השמותInspectionשיורשת מ-Vehicle. לאופנועים יש מאפייןHasSidecar(בוליאני). הבנאי מקבל את מספר לוחית הרישוי ואת מצב הסירה הצדדית. הוסיפו מתודה בשםRev()שמחזירה"{LicensePlate} revs: Vroom!".Program.cs: בקובץ הראשי שלכם, תיצרו כלי רכב ותתרגלו גם המרה כלפי מעלה וגם המרה בטוחה כלפי מטה. צרוCarו-Motorcycleבאמצעות ערכי קלט, ואז אחסנו את שניהם במערך של הפניות מסוגVehicle(המרה כלפי מעלה). עברו בלולאה על המערך והדפיסו את המידע הבסיסי של כל כלי רכב. לאחר מכן השתמשו במילת המפתחisעם התאמת תבניות כדי לבצע המרה בטוחה כלפי מטה: אם זהCar, קראו ל-Honk(); אם זהMotorcycle, קראו ל-Rev().
תקבלו ארבעה ערכי קלט:
- מספר לוחית הרישוי של המכונית
- מספר הדלתות
- מספר לוחית הרישוי של האופנוע
- האם יש סירה צדדית (
trueאוfalse)
הדפיסו את הפלט בפורמט הזה עבור כל כלי רכב במערך:
{GetBasicInfo() result}
{Honk() or Rev() result based on actual type}לדוגמה, אם ערכי הקלט הם ABC-123, 4, XYZ-789 ו-false, הפלט אמור להיות:
Vehicle: ABC-123
ABC-123 honks: Beep beep!
Vehicle: XYZ-789
XYZ-789 revs: Vroom!שימו לב שכל כלי הרכב מאוחסנים כהפניות מסוג Vehicle (המרה כלפי מעלה), אבל אפשר לזהות בבטחה את הסוגים האמיתיים שלהם ולגשת למתודות הספציפיות לסוג באמצעות תחביר התאמת התבניות של is לצורך המרה כלפי מטה!
נסו בעצמכם
using System;
using Inspection;
class Program
{
public static void Main(string[] args)
{
// קראו את הקלטים
string carPlate = Console.ReadLine();
int numberOfDoors = Convert.ToInt32(Console.ReadLine());
string motorcyclePlate = Console.ReadLine();
bool hasSidecar = Convert.ToBoolean(Console.ReadLine());
// TODO: צרו אובייקט Car באמצעות carPlate ו-numberOfDoors
// TODO: צרו אובייקט Motorcycle באמצעות motorcyclePlate ו-hasSidecar
// TODO: צרו מערך של הפניות מסוג Vehicle המכיל את שני כלי הרכב (המרה כלפי מעלה)
// TODO: עברו על המערך, ועבור כל כלי רכב:
// - הדפיסו את התוצאה של GetBasicInfo()
// - השתמשו במילת המפתח 'is' עם התאמת תבניות כדי לבצע המרה בטוחה כלפי מטה:
// - אם הוא מסוג Car, קראו ל-Honk() והדפיסו את התוצאה
// - אם הוא מסוג Motorcycle, קראו ל-Rev() והדפיסו את התוצאה
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמרחבי שמות והנחיותמבוא למחלקות ולאובייקטיםמילת המפתח 'this'מתודות ופרמטריםשדות לעומת מאפייניםבנאיםאתחול אובייקטיםסיכום – מחשבון פשוט4ירושה
תחביר ירושה בסיסית (:)מילת המפתח 'base'מילות המפתח Virtual ו-Overrideמחלקות Sealedמחלקת הבסיס 'object'סיכום – היררכיית עובדים7תכונות מתקדמות
העמסת אופרטוריםאינדקסרים (this[])דריסת ToString()מתודות הרחבהסיכום – רשימה מותאמת אישית2מאפיינים וחברים סטטיים
מאפיינים במימוש אוטומטימאפיינים לקריאה בלבד ולכתיבה בלבדשדות ומתודות סטטייםמחלקות סטטיותחברים עם גוף ביטוי5פולימורפיזם וממשקים
פולימורפיזם בזמן קומפילציה לעומת בזמן ריצהממשק לעומת מחלקה מופשטתממשקים מרוביםממשקים מפורשיםהמרה כלפי מעלה והמרה כלפי מטהחזרה: מחשבון צורות8מושגים מתקדמים בתכנות מונחה עצמים
קומפוזיציה במקום ירושהGenerics (מחלקות ומתודות)נציגים ואירועיםמאפיינים ורפלקציהIDisposable והצהרת usingיסודות הזרקת תלויותתרגלו בעצמכם: קומפיילר C# אונליין