מדריך התוכנה של רונן

תיכנות, תוכנה,

partia class

partia class – או בעברית "הכלה" או שיטות חלקיות
בפוסט זה אסביר מה היא מחלקה חלקית? מה הם היתרונות של שימוש partial class וכיצד ליישם את מחלקות חלקיות ביישומי #C.

partial class הינה מחלקה שמכילה מחלקה נוספת בעלת אותה שם וביחד משלימים מחלקה אחת מאותו סוג על מנת שתנאי זה יתקיים חובה שבכל אותם קבצים "מוכלים" תהיה הצהרה בראש הדף.

public partial class A { }
//public class A { } // Error, must also be marked partial

partial class היא תכונה שנוספה ל – Visual 2.0 2005 ההיסטורית ונתמכת גם ב -.2.0 NET Framework

הרעיון שעומד מאחורי partial הוא שניתן לפצל את  class או struct, או Interface לשני קבצים או יותר השייכים למחלקת האב. כל קובץ מקור מכיל סעיף של הגדרת המחלקה, וכל החלקים יתקמפלו בשלב ההידור (קומפילציה) לקובץ יישום אחד ויחיד בשם מחלקת האב למשל Customer.cs.

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

כל החלקים חייבים להיות זמינים בזמן ההידור כדי ליצור את הסוג הסופי. כל החלקים חייבים להיות זהה לנגישות, למשל: private, public, abstact, protected, וכן הלאה.

שיטות חלקיות:

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

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

היתרונות שיש למחקות חלקיים רבים:

  • כאשר עובדים על פרויקטים גדולים, ששייכים למחלקה ספציפית ורוצים לאפשר למתכנתים רבים לעבוד על אותה מחלקה בו זמנית צריך לאפשר את היכולת לאחד אח"כ את כל המחלקות הנגזרות מבלי ליצור מחדש את קובץ המקור.
  • ניתן לכתוב חלק ממחלקה שמבצעת פעולה כלשהי שחוזרת על עצמה (גם בפרויקטים אחרים) ולהפוך אותה ל DLL ולעשות בה שימוש חוזר.
  • ניתן להשתמש בה לצורך הוספת Attribute בקלאסים משתנים למשל אם ניקח class שניבנה ב model של Entity Framework אז בכל פעם שנבצע שינוי כלשהו במבנה הנתונים ונבצע סנכרון בין בסיס הנתונים ל model אז המחלקה תקבל שוב את ה properties שקיימים בבסיס נתונים וכל הרחבה או שינוי שביצענו על אותו קלאס ימחקו, לכן חשוב להוציא את הטיפול הנתונים שיחזרו ל class נפרד. מכיוון שלא ניתן לתת קלאסס עם שם דומה בפרוייקט כי אז תהיה התנגשות והקומפיילר יזרוק שגיאה כי לא יידע לאיזה קובץ להתייחס אנו חייבים לציין לו שהקובץ בעל אותו שם הוא הרחבה (הכלה) של הקלאס הקיים באמצעות המילה השמורה partial.
  • שימוש נוסף שניתן לעשות בהפרדות כאלו הן בשימוש בשפות שונות שאז בהתאם אפשר להגיד איזה חלק מורחב יטפל במחלקת האב.

יש כמה דברים שאתה צריך להיות זהיר לגבי עת כתיבת קוד לכיתות חלקיות: 

  • שם המחלקה ופרמטרים גנריים מהסוג חייבים להתאים בכל הגדרות חלקית מהסוג. סוגים גנרי יכולים להיות חלקיים. כל הצהרה החלקית חייבת להשתמש באותם שמות פרמטר באותו סדר.
  • מילות מפתח בהגדרה חלקית מהסוג הבא הם אופציונליים, אבל אם הוא קיים בהגדרה חלקית מסוג אחד, לא יכול להתנגש עם מילות מפתח שצוינו בהגדרה נוספת חלקית עבור אותו הסוג:
  • כל ההגדרות במחלקת ההכלה חייבות להתחיל עם מילת המפתח "partial".
  • כל מחלקות ההכלה אמורים להיות מאותו סוג של מחלקת האב, להשתמש באותם מודולים/חתימות מתודה ייחודיות למוקלד במצטבר (שהוגדר באופן חלקי).
  • אם חלק כלשהו הוא מופשט, כל ההחלה היא מופשטת, ירושה בכל סוג הכלה חלה על כל המחלקה.
  • שיטות חלקיות לקבל נ"צ אבל לא את הפרמטרים.
  • שיטות חלקיות הן בצורה מרומזת סוד של private ולכן לא יכולים להיות וירטואליים.
  • partial לא זמין בהצהרות delegate or enumeration declarations.

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

class Container
{
    partial class Nested
    {
        void Test() { }
    }
    partial class Nested
    {
        void Test2() { }
    }
}

בזמן הידור, תכונות של הגדרות חלקית מהסוג ימוזגו. לדוגמא, שקלו את ההצהרות הבאות:

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

הם שווי ערך להצהרות הבאות:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

המחשת הידור של שתי החלות ע"י קריאה בודדת:

public partial class CoOrds
{
    private int x;
    private int y;

    public CoOrds(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

public partial class CoOrds
{
    public void PrintCoOrds()
    {
        Console.WriteLine("CoOrds: {0},{1}", x, y);
    }
}

class TestCoOrds
{
    static void Main()
    {
        CoOrds myCoOrds = new CoOrds(10, 15);
        myCoOrds.PrintCoOrds();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
// Output: CoOrds: 10,15

 

הדוגמא הבאה מראה שאפשר לעבוד גם על struct ועל interface חלקיים.

partial interface ITest
{
    void Interface_Test();
}

partial interface ITest
{
    void Interface_Test2();
}

partial struct S1
{
    void Struct_Test() { }
}

partial struct S1
{
    void Struct_Test2() { }
}

,