CSharp 9.0 סי-שארפ שפה מאוד יציבה אך היא מוכיחה שוב ושוב בגמישותה.
Top-level statements כל פעם שיצרנו פרוקייט חדש ב-C# הוא יצר לנו קובץ בשם Main.cs
עם המחלקה הבאה:
1 2 3 4 5 6 7 8 9 10 11 12 using System;namespace MyNameSpace { class Program { static void Main (string [] args ) { Console.WriteLine("Hello World!" ); } } }
כדי לכתוב תכנית פשוטה היינו צריכים:
חייבים לייבא את System
.
להשתמש ב-Namespace
.
ליצור מחלקה - Program
.
ליצור פונקציית Main
.
זה קוד שאנחנו קוראים לו Boilerplate code
- קוד משוכפל. הוא הכרחי, הוא קיים, והוא קיים בכל כך הרבה קבצים ופרוייקטים אך אי אפשר להוריד אותו ללא תמיכת השפה.
Boilerplate code קוד שהוא Boilerplate
בדרך כלל אפילו לא נקרא אלה רק קיים שם כדי להוכיח את קיומו. כל משפטי ה-using
הם כאלו. הצהרה על מחלקת Program
היא כזו.
ב-C# נלחמים בתופעה הזו החל מגרסאותיה הראשונות: התכונה הראשונה שבאמת נלחמה ב-boilerplate
אלה הם התכונות - properties
.
במקום לכתוב את הדבר הבא:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Person { private string mName; public string GetName () { return mName; } public void SetName (string name ) { mName = name; } }
הקומפיילר יודע לייצר לנו קוד כזה ע”י שימוש ב-properties
:
1 2 3 4 public class Person { public string Name { get ; set ;} }
מאחורי הקלעים הוא עדיין יוצר שני מתודות ל-get
ו-set
וfield
אבל הקומפיילר עושה את זה עבורנו.
Records מאפיינים גרמו לנו לכתוב הרבה מחלקות עם מידע בלבד - מחלקות כאלו נקראות מודלים - Models.
1 2 3 4 5 6 public class Person { public string FirstName { get ; set ; } public string LastName { get ; set ; } public int Age { get ; set ; } }
שזה לשם עצמו יצר boilerplate.
כדי לתקן את זה יצרו מחלקות חדשות בשם records
:
1 public record Person (string FirstName, string LastName, int Age ) ;
כעת ניתן בשורה אחת ליצור מודלים עם Type
משלנו. ליצור Type
בהתאמה אישית עוזרת לנו ליצור ספריות יותר ברורות. ניתן היה להשתמש ב-ValueTuple<string,string,int>
אך זה אף פעם לא נוח כי אין לנו שמות לפונקציות ולמידע של המחלקה.
איך סי-שארפ לקחה את זה מקוטלין
Kotlin הביאה איתה חידושים רבים וכמוני רואים בה כמחליפת Java בחלק מהטכנולוגיות. זה לא נכון לומר את זה לכל הטכנולוגיות אך למשל ל-Android ניתן כבר להשתמש ב-Kotlin.
Kotlin הקדימה את סי-שארפ עם Records, שם זה נקרא Data Classes
.
ניתן לקרוא על זה כאן:https://kotlinlang.org/docs/data-classes.html
זה נראה כך:
1 data class User (val name: String, val age: Int )
הקסם של הקומפיילר הקומפיילר של C# מייצר לנו קוד רב.
אם לקחת את דוגמת ה-Record
השורה למעלה מייצרת לנו את הקוד הבא מאחורי הקלעים:
RecordUnderTheHood
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 using System;using System.Collections.Generic;using System.Diagnostics;using System.Runtime.CompilerServices;using System.Text;namespace ConsoleApp1 { [NullableContext(1) ] [Nullable(0) ] public class Person : IEquatable <Person > { [CompilerGenerated ] [DebuggerBrowsable(DebuggerBrowsableState.Never) ] private readonly string \u003CName\u003Ek__BackingField; [CompilerGenerated ] [DebuggerBrowsable(DebuggerBrowsableState.Never) ] private readonly int \u003CAge\u003Ek__BackingField; [CompilerGenerated ] [DebuggerBrowsable(DebuggerBrowsableState.Never) ] private readonly string \u003CStreet\u003Ek__BackingField; public Person (string Name, int Age, string Street ) { this .\u003CName\u003Ek__BackingField = Name; this .\u003CAge\u003Ek__BackingField = Age; this .\u003CStreet\u003Ek__BackingField = Street; base .\u002Ector(); } [CompilerGenerated ] protected virtual Type EqualityContract { [CompilerGenerated ] get { return typeof (Person); } } public string Name { [CompilerGenerated ] get { return this .\u003CName\u003Ek__BackingField; } [CompilerGenerated ] init { this .\u003CName\u003Ek__BackingField = value ; } } public int Age { [CompilerGenerated ] get { return this .\u003CAge\u003Ek__BackingField; } [CompilerGenerated ] init { this .\u003CAge\u003Ek__BackingField = value ; } } public string Street { [CompilerGenerated ] get { return this .\u003CStreet\u003Ek__BackingField; } [CompilerGenerated ] init { this .\u003CStreet\u003Ek__BackingField = value ; } } [CompilerGenerated ] public override string ToString () { StringBuilder builder = new StringBuilder(); builder.Append(nameof (Person)); builder.Append(" { " ); if (this .PrintMembers(builder)) builder.Append(' ' ); builder.Append('}' ); return builder.ToString(); } [CompilerGenerated ] protected virtual bool PrintMembers (StringBuilder builder ) { RuntimeHelpers.EnsureSufficientExecutionStack(); builder.Append("Name = " ); builder.Append((object ) this .Name); builder.Append(", Age = " ); builder.Append(this .Age.ToString()); builder.Append(", Street = " ); builder.Append((object ) this .Street); return true ; } [NullableContext(2) ] [CompilerGenerated ] public static bool operator !=(Person left, Person right) { return !(left == right); } [NullableContext(2) ] [CompilerGenerated ] public static bool operator ==(Person left, Person right) { if ((object ) left == (object ) right) return true ; return (object ) left != null && left.Equals(right); } [CompilerGenerated ] public override int GetHashCode () { return ((EqualityComparer<Type>.Default.GetHashCode(this .EqualityContract) * -1521134295 + EqualityComparer<string >.Default.GetHashCode(this .\u003CName\u003Ek__BackingField)) * -1521134295 + EqualityComparer<int >.Default.GetHashCode(this .\u003CAge\u003Ek__BackingField)) * -1521134295 + EqualityComparer<string >.Default.GetHashCode(this .\u003CStreet\u003Ek__BackingField); } [NullableContext(2) ] [CompilerGenerated ] public override bool Equals (object obj ) { return this .Equals(obj as Person); } [NullableContext(2) ] [CompilerGenerated ] public virtual bool Equals (Person other ) { if ((object ) this == (object ) other) return true ; return (object ) other != null && this .EqualityContract == other.EqualityContract && EqualityComparer<string >.Default.Equals(this .\u003CName\u003Ek__BackingField, other.\u003CName\u003Ek__BackingField) && EqualityComparer<int >.Default.Equals(this .\u003CAge\u003Ek__BackingField, other.\u003CAge\u003Ek__BackingField) && EqualityComparer<string >.Default.Equals(this .\u003CStreet\u003Ek__BackingField, other.\u003CStreet\u003Ek__BackingField); } [CompilerGenerated ] public virtual Person \u003CClone\u003E\u0024() { return new Person(this ); } [CompilerGenerated ] protected Person (Person original ) { base .\u002Ector(); this .\u003CName\u003Ek__BackingField = original.\u003CName\u003Ek__BackingField; this .\u003CAge\u003Ek__BackingField = original.\u003CAge\u003Ek__BackingField; this .\u003CStreet\u003Ek__BackingField = original.\u003CStreet\u003Ek__BackingField; } [CompilerGenerated ] public void Deconstruct (out string Name, out int Age, out string Street ) { Name = this .Name; Age = this .Age; Street = this .Street; } } }
כמה דברים חשובים שאנו רואים פה:
ToString הקומפיילר מייצר לנו ToString
לכל ה-Member
ים.
1 2 Person p = new Person("Bob" , "Bobson" , 42 ); Console.WriteLine(p.ToString());
מודפס:
Person { FirstName = Bob, LastName = Bobson, Age = 42 }
.
Equals ו- == העמסות חשובות כדי לבדוק האם שני אובייקטים הם שווים או אותם מופעים.
1 2 3 4 5 6 Person p2 = new ("Alice" , "Alison" , 37 ); Person p3 = p; Console.WriteLine(p == p2); Console.WriteLine(p.Equals(p2)); Console.WriteLine(p == p3);
שימו לב שפה אנו משמיטים גם את סוג המחלקה כאשר אנו משתמשים ב-new
. פיצ’ר חדש של C# 9!
יודפס:
Deconstruct לבצע פירוק לגורמים של המחלקה:
1 2 3 4 5 Person p = new ("Bob" , "Bobson" , 42 ); (string FirstName, string LastName, _) = p; Console.WriteLine(FirstName); Console.WriteLine(LastName);
יודפס:
שימו לב שניתן בעזרת _
להשמיט פרמטרים שלא רוצים אותם!
החידושים של C# תמיד הכי מודרניים וכבר שני עשורים שהיא מובילה בתכונותיה ובטכנולוגיות שלה. ניתן ליצור ממשקי משתמש דסקטופיים, לפתח משחקים, שרתים, APIים ועוד!
תודה על הקריאה :)