בחינת איגוד מאוחר עם נציגים

הושלם

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

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

ב- C#, נציגים משמשים ליישום איגוד מאוחר.

מהו נציג?

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

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

הדוגמה הבאה מראה כיצד להגדיר סוג נציג:


public delegate int PerformCalculation(int x, int y);

דוגמה זו מגדירה נציג בשם PerformCalculation. הנציג PerformCalculation מוגדר לייצוג שיטות המקבלות שני int פרמטרים (x ו- y) ומחזירות int. ניתן להשתמש בנציג זה לסיכום שיטות המבצעות חישובים שונים, כגון חיבור, חיסור, כפל, חילוק או משוואות מורכבות יותר המשתמשות בשני הפרמטרים.

לדוגמה, ניתן להשתמש בנציג זה כדי לסיכום השיטות הבאות:


public class Calculator
{
    public int Add(int x, int y)
    {
        return x + y;
    }

    public int Subtract(int x, int y)
    {
        return x - y;
    }

    public int Multiply(int x, int y)
    {
        return x * y;
    }

    public int Divide(int x, int y)
    {
        if (y == 0)
            throw new DivideByZeroException();
        return x / y;
    }
}

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

הקוד הבא מראה כיצד להשתמש בנציג PerformCalculation :


public class Program
{
    public static void Main()
    {
        Calculator calculator = new Calculator();

        // Create delegate instances
        PerformCalculation add = new PerformCalculation(calculator.Add);
        PerformCalculation subtract = new PerformCalculation(calculator.Subtract);
        PerformCalculation multiply = new PerformCalculation(calculator.Multiply);
        PerformCalculation divide = new PerformCalculation(calculator.Divide);

        // Call the methods using the delegates
        Console.WriteLine("Addition: " + add(5, 3)); // Output: 8
        Console.WriteLine("Subtraction: " + subtract(5, 3)); // Output: 2
        Console.WriteLine("Multiplication: " + multiply(5, 3)); // Output: 15
        Console.WriteLine("Division: " + divide(5, 3)); // Output: 1
    }
}

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

מאפייני סוג נציג

נציגים הם סוגי הפניה, כלומר שהם מאוחסנים בערם ובאפשרותך להעביר אותם ממקום למקום כמו כל אובייקט אחר. בעת יצירת מופע נציג, אתה יוצר אובייקט שכוף פעולת שירות. כיתוב זה מאפשר לך להתייחס לנציג אובייקט ממחלקה ראשונה, בדיוק כמו לכל אובייקט אחר ב- C#. באפשרותך ליצור מופעים של נציגים, להקצות אותם למשתנים ולהקצות אותם כארגומנטים לשיטות. התהליך דומה לאופן שבו אתה עובד עם אובייקטים אחרים ב- C#, כגון מחרוזות או רשימות.

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

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

לנציגים יש את המאפיינים הבאים:

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

הערה

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

מדוע כדאי להשתמש בנציגים?

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

נציגים מספקים יתרונות רבים, כולל הפריטים הבאים:

  • גמישות: נציגים מאפשרים לך להעביר שיטות שונות כפרמטרים, דבר המאפשר אופן פעולה דינאמי בהתבסס על תנאי זמן ריצה. גמישות זו שימושית כאשר הפעולה המדויקת שיש לבצע נקבעת בזמן ריצה.
  • הרחבה: עם נציגים, באפשרותך להרחיב בקלות את הפונקציונליות על-ידי הוספת פעולות חדשות מבלי לשנות את הקוד הקיים. באפשרותך להעביר כל שיטה התואמת לחתימה של הנציג.
  • Decoupling: Delegates decouple the methodvocation from the method definition, making the code more modular and easier to maintain.

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

בקשת שיטה דינאמית

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

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

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

שיטות התקשרות חזרה

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

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

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

סוג בטיחות

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

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

הפתרון: נציגים מספקים הפניות לפעולת שירות מסוג type-safe, ומבטיחים שחתימות פעולת השירות יתאימו לחתימה של הנציג. פעולה זו מונעת שגיאות זמן ריצה והופכת את הקוד ל חזק יותר.

בקשת שידור לקבוצה

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

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

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

שיטות עבודה מומלצות להצהרת נציגים ב- C#‎

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

הגדרת נציגים בחלק העליון של קובץ כיתה

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

הקוד הבא מראה כיצד ליישם נציג המוגדר מחוץ לכיתה:


namespace MyNamespace

// Define the delegate outside the class
public delegate void MyDelegate(string message);

public class Publisher
{
    // Method that uses the delegate
    public void PublishMessage(MyDelegate del)
    {
        del("Hello from Publisher!");
    }
}

public class Subscriber
{
    public void Subscribe()
    {
        // Create an instance of the Publisher class
        Publisher publisher = new Publisher();

        // Create an instance of the delegate and pass a method to it
        MyDelegate del = new MyDelegate(PrintMessage);

        // Call the method of the Publisher class and pass the delegate
        publisher.PublishMessage(del);
    }

    // Method that matches the delegate signature
    public void PrintMessage(string message)
    {
        Console.WriteLine(message);
    }
}

הגדרת נציגים בכיתה

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


namespace MyNamespace

public class Publisher
{
    // Define a public delegate
    public delegate void MyDelegate(string message);

    // Method that uses the delegate
    public void PublishMessage(MyDelegate del)
    {
        del("Hello from Publisher!");
    }
}

public class Subscriber
{
    public void Subscribe()
    {
        // Create an instance of the Publisher class
        Publisher publisher = new Publisher();

        // Create an instance of the delegate and pass a method to it
        Publisher.MyDelegate del = new Publisher.MyDelegate(PrintMessage);

        // Call the method of the Publisher class and pass the delegate
        publisher.PublishMessage(del);
    }

    // Method that matches the delegate signature
    public void PrintMessage(string message)
    {
        Console.WriteLine(message);
    }
}


נקודות עיקריות

  • נציגים הם סוגי .NET הנגזרים מהמחלקה Delegate שמרכיבים שיטות.
  • נציגים מאפשרים לך להעביר שיטות כפרמטרים, לאחסן אותן במשתנים ולהפעיל אותן בזמן ריצה.
  • נציגים הם מסוג 'סוג בטוח', כלומר המהדר בודק שחתימות פעולת השירות תואמות לחתימה של הנציג בזמן ההידור.
  • נציגים יכולים לשמש עבור בקשת שיטה דינאמית, שיטות התקשרות חזרה, סוג בטיחות והפעלת שידור לקבוצה.
  • נציגים הם הבסיס לטיפול באירועים ב- C#‎.
  • נציגים יכולים להיות משרשרים יחד, ומאפשרים הפעלת שיטות מרובות עם נציג יחיד.
  • נציגים מוגדרים בדרך כלל מחוץ לכיתה כדי לאפשר גישה מכיתות אחרות מבלי שיצטרכו ליצור מופעים של הכיתה.