Delegate
Delegate
- הוא טיפוס שמצביע לפונקציה
כל פונקציה השם שלה
זה רק הצבעה למיקום של הקוד בזיכרון הפונקציה יושבת בזיכרון והשם שלה מחזיק את
הכתובת (אפשר גם לגשת ישירות לזיכרון אילו היינו יודעים את הכתובת) – Delegate משמש כמצביע לפונקציה.
הגדרת delegate מתבצעת באמצעות המילה השמורה delegate ולאחריה חתימה של
פונקציה, כאשר שם "הפונקציה" הוא למעשה שם ה- delegate.
delegate int Calc(int x, int y);
Delegate יכול להצביע רק על פונקציות
שחתימתן היא בדיוק כמו חתימת ה- delegate. כלומר, הוא יוכל לייצג כל פונקציה שעונה לתנאים אלו בלבד – מקבלת
שני מספרים שלמים (int)
ומחזירה מספר שלם.
קוד פשוט להבנת
הבסיס של delegate
3 – יצירת delegate שמקבל 2 מספרים לא שלמים
ומחזיר מספר
15-22 – יצרנו 2
פונקציות שמקבלות 2 מספרים ומבצעות חישוב ומחזירות ערך
8 – יצרנו אובייקט
חדש של ה delegate שמקבל את הפונקציה הראשונה
9 – קריאה לפונקציה
הראשונה באמצעות הפונקציה של ה delegate
11- החלפת הפונקציה
שבתוך המצביע לפונקציה אחרת
12 – קריאה שנית
לפונקציה
למעשה קראנו לאותה
הפונקציה פעמיים אך בכל פעם היא הצביעה על פונקציה אחרת ולכן התבצע חישוב אחר
1. namespace ConsoleApplication15
2. {
3. delegate double MetOperator(double a, double b);
4. class Program
5. {
6. static void Main(string[] args)
7. {
8. MetOperator fucAddress = new MetOperator(add);
9. double sum = fucAddress (10, 5);
10. Console.WriteLine(sum);
11. fucAddress = new MetOperator(Sub);
12. double sub = fucAddress (15, 10);
13. Console.WriteLine(sub);
14. }
15. static double add (double a , double b)
16. {
17. return a + b;
18. }
19. static double Sub(double a, double b)
20. {
21. return a - b;
22. }
23. }
24. }
אחרי שהבנו את הרעיון איך הפונקציה עובדת ניתן
להגדיר בצורה פשוטה יותר
MetOperator
fucAdd = (add);
fucAdd = (Sub);
המערכת יוצרת לבד את האובייקט
מדוע צריך delegates כאשר אפשרי לקרוא
לפונקציה ?
- ה Delegate נותן עוד הפשטה לקוד ע"י ניתוק הקשר הישיר בין הרכיבים
- לא תמיד כותב הקוד יודע את שם הפונקציה (ואולי עדיין לא נכתבה) או שהפונקציה נמצאת במחלקה אחרת ואין לו גישה לכן הוא פונה ל Delegate שקורא לפונקציה
Multicast delegate
מכיוון שה delegate הוא בעצם אובייקט ולכן הוא יכול להכיל מספר פונקציות שמתאימות לחתימה
הוספת פונקציה באמצעות +=
static void Main(string[] args)
{
MetOperator fucAddress;
fucAddress = new MetOperator(add);
double result = fucAddress (10 , 5 );
Console.WriteLine(result);
fucAddress += new MetOperator(Sub);
result = fucAddress(10, 5);
Console.WriteLine(result);
}
static double add (double a , double b)
{
return a + b;
}
static double Sub(double a, double b)
{
return a - b;
}
בפעם הראשונה קראנו לפונקציה אחת וקיבלנו תשובה –
בפעם השנייה המערכת מריצה את 2 הפונקציות ולכן התוצאה שונה (נקבל את התוצאה שלה
פונקציה השנייה)
Generics \ Collections
תכנות גנרי - לעיתים נרצה לבנות מחלקות אשר מאד דומות
בתבניתם, ושונות רק בסוג הנתונים שהם מחזיקות. במקום לכתוב את אותה המחלקה מספר
פעמים וכל פעם תקבל סוג אחר של משתנה. הפתרון הינו תכנות גנרי, תכנות שבו איננו מגדירים את סוג המשתנה אלא מציינים "סוג כלשהו"
המנגנון מאפשר כתיבת מתודות, מחלקות, ממשקים ו- Delegates המגדירים "טיפוס כללי", או לחילופין להשתמש במחלקות הכתובות כבר והן חלק מה- Framework.
"טיפוס כללי" אינו טיפוס אמיתי בתוכנית, אלא מתפקד כשומר מקום לטיפוס אמיתי שיוגדר בעת השימוש במחלקה/מתודה, הקישור לטיפוס האמיתי מתבצע בזמן ריצה.
טיפוס כללי יוגדר בין סוגריים משולשים, לדוגמה: <T>.
נ.ב לעבודה גנרית נדרשת הספרייה using
System.Collections.Generic; (בVS נוסף באופן
אוטומטי)
Collections
דוג' פשוטה לפונקציה גנרית – הפונקציה יכולה לקבל כל ערך באמצעות
ההגדרה <T>
ובכל קריאה מגדירים מה סוג הערך שתקבל
namespace
ConsoleApp6
{
class person
{
public int id { get; set; }
public void stem<T>( T a , T b)
{
Console.WriteLine(a.ToString() + b.ToString());
}
}
class Program
{
static void Main(string[] args)
{
int x = 8;
int y = 11;
person p1 = new person();
p1.stem<int>(x, y);
p1.stem<string>("hii - ", "dodo");
}
}
דוג' נוספת – כל list
הוא מחלקה גנרית שביצירה מגדירים את הסוג של אובייקטים שיכיל
List יכול לקבל גם יותר
מסוג אחת של אובייקט באמצעות הגדרת רשימה של אובייקטים
namespace
ConsoleApp6
{
class person
{
public int id { get; set; }
public string noame { get; set; }
public person(int id , string name)
{
this.id = id;
this.noame = noame;
}
}
class Program
{
static void Main(string[] args)
{
List<person> listGenerics = new List<person>();
listGenerics.Add(new person(1, "dodo"));
listGenerics.Add(new person(2, "nosha"));
}
}
מחלקה גנרית
בהגדרת מחלקה גנרית נוכל להגדיר כל משתנה\ פונקציה
במחלקה כגנרי וליצור אובייקט לפי הסוג שנבחר ביצירת האובייקט
namespace
ConsoleApp6
{
class Generic<T>
{
public T id;
public T name;
public void print(T a, T b)
{
Console.WriteLine($"{ a.ToString()} - {b}");
}
public Generic(T id , T name)
{
this.id = id;
this.name =
name;
}
}
class Program
{
static void Main(string[] args)
{
Generic<string> g1 = new Generic<string>("aa "
,"avi");
Generic<int> g2 = new Generic<int>(123, 444);
}
}
}
List.sort()
- IComparable
בכל List מספרי ישנה פונקציה שמסדרת אותו (גם ליסט שמקבל string או char אבל גם שם זה בגלל הערך המספרי של האותיות). כל מה שעלינו לעשות
הוא לכתוב list.sort()
והרשימה תסתדר.
אך כאשר יש לנו רשימה שמורכבת מכמה ערכים מספריים
אנחנו צריכים להורות למחשב איזה ערך לבצע את הסדר, נשתמש ב
interface מובנה בשם IComparable.
אנחנו מגדירים ל
interface על
איזה שדה לבצע את הסדר והמערכת רצה על כל הרשימה ובודקת ומסדרת לפני התוצאה של result במידה ונרצה להפוך את
הסדר נשנה את ה result
בין ה1 ל-1
public class Player :IComparable<Player>
{
public string Name { get; set; }
public int Total { get; set; }
public Player(string name, int total)
{
Name = name;
Total = total;
}
public int CompareTo(Player obj)
{
int result = 0;
Player f = obj as Player;
if (Total > f.Total) result = 1;
if (this.Total < f.Total) result = -1;
return result;
}
}
class Program
{
static void Main(string[] args)
{
List<Player> lst = new List<Player>();
lst.Add(new Player("John", 100));
lst.Add(new Player("Smith", 120));
lst.Add(new Player("Cait", 97));
lst.Sort();
foreach (var t in lst)
{
Console.WriteLine(t.Name + " - " + t.Total);
}
}
QUEUE - Stack
2 אוספים
נוספים שמאפשרים שמירת אוסף נתונים
- בשונה LIST רגיל בתור ניתן לשמור כל סוג של אובייקט
- ניתן לגשת ישירות לראש\סוף התור ללא ציון המיקום ברשימה (מה שמחייב לבדוק מה האורך)
QUEUE – תור
עובד בשיטת First in first out - FIFO )מי
שנכנס ראשון יוצא ראשון)
- Enqueuer - פונקציה להכנסת אברים לסוף התור
- Peek – פקודה להחזרת הערך שתחילת התור – ללא להוציא אותו
- Dequeuer – לקבלת הערך שבתחילת התור - מוציא אתו מהרשימה
- Count - לספירת האברים בתור
- Clear - לניקוי התור
- Contains – חיפוש אלמנט בתור (אם קיים או לא)
קוד שמדגים את כל
הפונקציות שלמדנו ב QUEUE
public class Program
{
static void Main(string[] args)
{
Queue my_queue = new Queue();
my_queue.Enqueue("noam");
my_queue.Enqueue("dodo");
my_queue.Enqueue(1);
my_queue.Enqueue(100);
my_queue.Enqueue(null);
my_queue.Enqueue(2.4);
foreach (var ele in my_queue)
{
Console.WriteLine(ele);
}
Console.WriteLine($"Total elements present in
my_queue: {my_queue.Count}");
Console.WriteLine($"Total elements present in
my_queue: {my_queue.Dequeue()}");
Console.WriteLine($"Total elements present in
my_queue: {my_queue.Count}");
Console.WriteLine($"Total elements present in
my_queue: {my_queue.Peek()}");
Console.WriteLine((my_queue.Contains("dodo") == true) ? ("Element
available...!!") : ("Element
not available...!!"));
my_queue.Clear();
Console.WriteLine($"Total elements present in
my_queue: {my_queue.Count}");
}
}
Stack – ערימה (מחסנית)
עובד בשיטת LIFO - Last in
first out (מי שנכנס אחרון הראשון יוצא)
התור הוא חד כיווני ולכן האחרון שנכנס הוא שיצא ראשון
פקודות
- Push – להכניס ערכים לרשימה
- Pop – להוציא את האחרון שנכנס
- Peek – לקבל את האחרון נכנס
- Contains – חיפוש אלמנט בתור (בדוג' שלנו יחזיר True or False)
קוד שמדגים את כל
הפונקציות שלמדנו ב QUEUE
Stack myStack = new Stack();
myStack.Push("Element 1 ");
myStack.Push("Element 2 ");
myStack.Push(4.3);
myStack.Push(443);
Console.WriteLine($"Total number of elements in
the Stack are : {myStack.Count}");
foreach (var ele in myStack)
{
Console.WriteLine(ele);
}
Console.WriteLine("Element at the top is :
" + myStack.Peek());
myStack.Pop();
Console.WriteLine($"Total number of elements in
the Stack are : {myStack.Count}");
Console.WriteLine(myStack.Contains("noam"));
myStack.Clear();
Console.WriteLine($"Total number of elements in
the Stack are : {myStack.Count}");
אין תגובות:
הוסף רשומת תגובה