יום רביעי, 24 בינואר 2018

תכנות ג'נרי ב-#C

Generic

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



דוגמא - פונקציה ג'נרית להדפסת מערך פשוטה:
(אפשר לתת לסוג המשתנים כל שם, כאן נשתמש ב-"E".)
    class Program
    {
        // פונקציה ג'נרית להדפסה של איברי מערך מכל סוג מספרי
        static void PrintArray<E>(E[] inputArray)
        {
            foreach (E element in inputArray)
                Console.Write(element + ", ");
            Console.WriteLine("\n");
        }
 
 
        static void Main(string[] args)
        {
            // double ו int יצירת מערך של 
            int[] intArray = { 1, 2, 3, 4, 5, 6 };
            double[] doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
 
            // int הדפסת מערך
            PrintArray<int>(intArray); // 1, 2, 3, 4, 5, 6, :ידפיס
 
            // double הדפסת מערך
            PrintArray<double>(doubleArray); // 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, :ידפיס
        }
    }







דוגמא - מחלקה ג'נרית לייצוג נקודה:
(אפשר לתת לסוג המשתנים כל שם, כאן נשתמש ב-"T".)


    // מחלקה ג'נרית שמייצגת נקודה
    class Point<T>
    {
        private T x;
        private T y;
 
        public Point(T x, T y)
        {
            this.x = x;
            this.y = y;
        }
        public void show()
        {
            Console.WriteLine("x: {0}    y: {1}", x, y);
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            // נקודה של פרמטרים מספריים שלמים
            Point<int> IntP = new Point<int>(10, 5);
 
            // נקודה של פרמטרים מספריים עשרוניים
            Point<double> DoubleP = new Point<double>(10.5, 5.7);
 
            // נקודה של פרמטרים מסוג מחרוזת
            Point<string> StringP = new Point<string>("a7""b3");
 
            // הדפסה
            IntP.show();    // x: 10    y: 5      :ידפיס
            DoubleP.show(); // x: 10.5    y: 5.7  :ידפיס
            StringP.show(); // x: a7    y: b3     :ידפיס
        }
    }







דוגמא - מחלקה ג'נרית לייצוג נקודה עם שני סוגים שונים של צירים:
(אפשר לתת לסוג המשתנים כל שם, כאן נשתמש ב-"T1" ו-"T2".)
    // מחלקה ג'נרית שמייצגת נקודה עם שני סוגים שונים של צירים
    class Point<T1, T2>
    {
        private T1 x;
        private T2 y;
 
        public Point(T1 x, T2 y)
        {
            this.x = x;
            this.y = y;
        }
        public void show()
        {
            Console.WriteLine("x: {0}    y: {1}", x, y);
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            // נקודה של פרמטרים מספריים שלמים
            Point<intint> IntIntP = new Point<intint>(10, 5);
 
            // נקודה של פרמטר שלם ופרמטר עשרוני
            Point<intdouble> IntDoubleP = new Point<intdouble>(10, 5.7);
 
            // הדפסה
            IntIntP.show();    // x: 10    y: 5      :ידפיס
            IntDoubleP.show(); // x: 10    y: 5.7    :ידפיס
        }
    }











דוגמא - מחלקה ג'נרית לייצוג אדם עם "איזור מידע אישי" שיצרנו בעצמנו:
namespace ConsoleApplication72
{
    // ייצוג מבחר פרטים אישיים
    class PersonInformation
    {
        public int Age;
        public String Phone;
        public String Country;
        public PersonInformation(int Age, String Phone, String Country)
        {
            this.Age = Age;
            this.Phone = Phone;
            this.Country = Country;
        }
        public override string ToString()
        {
            return "Age: " + Age + "  Phone: " + Phone + "  Country: " + Country;
        }
    }
 
 
    // מחלקה שמייצגת אדם עם קובץ מידע שניתן לשנות
    class Person<T>
    {
        private int ID;
        private String FirstName;
        private String LastName;
        private T PersonalInformation;
 
 
        public Person(int ID, String FirstName, String LastName, T PersonalInformation)
        {
            this.ID = ID;
            this.FirstName = FirstName;
            this.LastName = LastName;
            this.PersonalInformation = PersonalInformation;
        }
 
        // ( מאפשר ליצור פונקציה בעלת שם שכבר קיים במחלקה שירשנו override )
        public override string ToString() 
        {
            return "Name: " + FirstName + " " + LastName + ".  ID: " + ID
            + "\nInformation:\n" + PersonalInformation + ".";
            //// String בעת ניסיון המרה משתמע ל toString מופעלת אוטומטית הפונקציה C# ב
            //// :באותה מידה היינו יכולים לכתוב
            //// return ID.ToString() + FirstName + LastName + PersonalInformation.ToString();
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            // יצירת קטע מידע על האדם
            PersonInformation info = new PersonInformation(25, "0503365542""Israel");
 
            // יצירת אדם בשילוב קטע המידע שיצרנו
            Person<PersonInformation> person1 =
                new Person<PersonInformation>(264738799, "Noam""Nol", info);
 
            // ToString() הפונקציה תמיד תפעיל אוטומטית את 
            Console.WriteLine(person1);
 
            // :ידפיס
            //Name: Noam Nol.  ID: 264738799
            //Information:
            //Age: 25  Phone: 0503365542  Country: Israel.
        }
    }
}









דוגמא - מחלקה לייצוג מעגל שיורשת באופן לא ג'נרי מהמחלקה הג'נרית "Point":
(ניתן להזין לנקודות הציון ולקוטר רק ערכים מסוג double)
    // מחלקה ג'נרית שמייצגת נקודה
    class Point<T>
    {
        private T x;
        private T y;
 
        public Point(T x, T y)
        {
            this.x = x;
            this.y = y;
        }
 
        public T GetX()
        {
            return x;
        }
 
        public void SetX(T x)
        {
            this.x = x;
        }
 
        public T GetY()
        {
            return y;
        }
 
        public void SetY(T y)
        {
            this.y = y;
        }
 
        public override string ToString()
        {
            return "x: " + x + ",    y: " + y;
        }
    }
 
 
    // שני מאפיינים יש למעגל בשטח דו ממדי: קוטר ונקודה
    // בלבד double כאן אנחנו יורשים את המחלקה "נקודה" בתצורה של
    class Circle : Point<double>
    {
        // קוטר מעגל
        private double Diameter;
 
 
 
        // פונקציה בונה
        public Circle(double x, double y, double Diameter)
            : base(x, y)
        {
            // משמש לגישה לשדות ופונקציות (ציבוריים) של המחלקה שירשנו ממנה base
            //  (override) שימושי לפונקציות בעלות שם זהה
            // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base
 
 
            this.Diameter = Diameter;
        }
 
 
 
        public double GetDiameter()
        {
            return Diameter;
        }
 
        public void SetDiameter(double Diameter)
        {
            this.Diameter = Diameter;
        }
 
        public override string ToString()
        {
            return base.ToString() + ",    Diameter: " + Diameter;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Circle circ = new Circle(20.4, 30.5, 100);
            Console.WriteLine(circ); // x: 20.4,    y: 30.5,    Diameter: 100    :ידפיס
        }
    }














דוגמא - מחלקה ג'נרית לייצוג מעגל שיורשת באופן ג'נרי מהמחלקה הג'נרית "Point":
    // מחלקה ג'נרית שמייצגת נקודה
    class Point<T>
    {
        private T x;
        private T y;
 
        public Point(T x, T y)
        {
            this.x = x;
            this.y = y;
        }
 
        public T GetX()
        {
            return x;
        }
 
        public void SetX(T x)
        {
            this.x = x;
        }
 
        public T GetY()
        {
            return y;
        }
 
        public void SetY(T y)
        {
            this.y = y;
        }
 
        public override string ToString()
        {
            return "x: " + x + ",    y: " + y;
        }
    }
 
 
    // שני מאפיינים יש למעגל בשטח דו ממדי: קוטר ונקודה
    // כאן אנחנו יורשים את המחלקה "נקודה" בתצורה ג'נרית
    class Circle<T> : Point<T>
    {
        // קוטר מעגל
        private T Diameter;
 
 
 
        // פונקציה בונה
        public Circle(T x, T y, T Diameter)
            : base(x, y) // Point שליחה לפונקציה בונה של המחלקה 
        {
            // משמש לגישה לשדות ופונקציות (ציבוריים) של המחלקה שירשנו ממנה base
            //  (override) שימושי לפונקציות בעלות שם זהה
            // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base
            // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/knowing-when-to-use-override-and-new-keywords
 
 
 
            this.Diameter = Diameter;
        }
 
 
 
        public T GetDiameter()
        {
            return Diameter;
        }
 
        public void SetDiameter(T Diameter)
        {
            this.Diameter = Diameter;
        }
 
        public override string ToString()
        {
            return base.ToString() + ",    Diameter: " + Diameter;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Circle<int> circ = new Circle<int>(20, 30, 100);
            Console.WriteLine(circ); // x: 20,    y: 30,    Diameter: 100    :ידפיס
        }
    }






תכנות ג'נרי עושה שימוש רב ב interface, נושא עליו נלמד בהמשך.
ראו גם: מדריך #C מתקדם - Generics: Constraints – התניות על פרמטרים גנריים



אין תגובות:

הוסף רשומת תגובה