86. var keyword

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

למשל, נניח שיש לנו מתודה כזאת:

1
2
3
4
5
6
7
8
public IEnumerable<Person> GetFamilyInfo(string familyName)
{
List<Person> result = new List<Person>();
// ...
return result;
}

אז אנחנו קוראים לה בצורה כזאת:

1
IEnumerable<Person> bananiFamily = GetFamilyInfo("Banani");

כבר בדוגמה פשוטה זו חזרנו על עצמנו מספר פעמים:

פעם ראשונה היא בשורה

1
List<Person> result = new List<Person>();

שימו לב שמצוין הטיפוס List<Person> פעמיים – פעם אחת בצד ימין ופעם אחת בצד שמאל,

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

באופן דומה, בשורה

1
IEnumerable<Person> bananiFamily = GetFamilyInfo("Banani");

מופיעה כפילות, אם כי יותר סמויה. הטיפוס IEnumerable<Person> מופיע הפעם רק בצד שמאל, אבל עצם העובדה שקראנו לפונקציה GetFamilyInfo, עשויה להסגיר שהטיפוס בצד שמאל אמור להיות IEnumerable<Person>.

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

לדוגמה, בשתי הדוגמאות שכתבנו, נוכל לכתוב במקום את הקוד הבא:

1
var result = new List<Person>();

הקומפיילר מזהה שהטיפוס של צד ימין הוא List<Person>, ולכן קובע את הטיפוס של result להיות List<Person>

באופן דומה,

1
var bananiFamily = GetFamilyInfo("Banani");

מאחר והפונקציה GetFamilyInfo מחזירה IEnumerable<Person>, הקומפיילר נותן לbananiFamily את הטיפוס IEnumerable<Person>


קיים בלבול נפוץ בין המילה השמורה var לבין הכנסת המשתנה לטיפוס object.

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

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

1
2
var result = new List<Person>();
result.Add(new Person()); // Compiles and works

אם, למשל, נחליף את המילה var בobject, השורה השנייה לא תתקמפל

1
2
object result = new List<Person>();
result.Add(new Person()); // Doesn't compile

בנוסף, ההשמה היא strongly typed, כלומר לא נוכל להחליף את הטיפוס באמצע:

1
2
var result = new List<Person>();
result = 3; // Won't compile, since result is of type List<Person>

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

1
2
object result = new List<Person>();
result = 3; // Compiles

הגבלות:

נוכל להשתמש בKeyword עבור משתנים מקומיים בלבד (לא נוכל לFields, ערכי החזר של פונקציה, ארגומנטים של פונקציה וכו’)

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


מתי להשתמש?

שימו לב שראינו שתי דוגמאות לשימוש בvar – אחד באתחול באמצעות Constructor, והשני בקריאה לפונקציה.

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

לכן, לא מומלץ להשתמש בvar עם משתנים שאנחנו מאתחלים אותם ע"י קריאה לפונקציה.

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

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

1
2
3
4
5
6
Dictionary<string, ICollection<ulong>> tableNamesToPks =
new Dictionary<string, ICollection<ulong>>();
// Use var instead
var tableNamesToPks =
new Dictionary<string, ICollection<ulong>>();

נימה אישית - אני לא מאוהדי var, ולא ממליץ להשתמש בזה, אלא אם זה לא פוגע בקריאות (למשל באתחול באמצעות Constructor באותה שורה)

שבוע גשום טוב

שתף