עד כה ראינו מספר דרכים להשיג Type בזמן ריצה.
ראינו גם מספר דברים שאפשר לעשות על Type כזה, למשל למצוא את הממשקים שהוא מממש ועוד.
אחד הדברים המגניבים ביותר שאפשר לעשות על Type כזה הוא ליצור instance חדש מהסוג שלו בזמן ריצה.
למשל, נניח שיש לנו מחלקה המייצגת צורה:
|
|
עכשיו, כל אחד יכול לממש צורה בדרך שלו. אנחנו רוצים לאפשר ליצור צורה לפי השם שלה:
|
|
הדרך האינטואיטיבית היא לעשות משהו כזה:
|
|
או כזה:
|
|
המימוש הזה נחמד, אבל יש איתו שתי בעיות עיקריות:
- הוא עובד רק על הTypeים שאנחנו מכירים, ולא מאפשר להוסיף Typeים של משתמשים אחרים. כלומר, אם מישהו מימש צורה חדשה, לא נדע זאת.
- יש בו טיפול ספציפי בכל סוג צורה שיש. כך שכל פעם שנוסיף צורה, נצטרך לעדכן את הפונקציה הזו.
ראו גם טיפ 50.
כדי לפתור את זה, נוכל להשתמש בReflection כדי ליצור instance של צורה לפי הType שלה באופן דינאמי.
(נוכל למשל, להשתמש בType.GetType כדי להשיג את הType של הצורה לפי השם שלו)
כדי ליצור instance חדש לפי Type, קיימת הפונקציה הסטטית Activator.CreateInstance.
הOverload הכי פשוט שלה מקבל Type ופרמטרים, וקורא לConstructor הכי מתאים של הType עם הפרמטרים.
נוכל להשתמש בו למשל כדי לממש את הShapeFactory:
|
|
ככה יצרנו בעצם צורה בהינתן השם שלה בזמן ריצה.
(שימו לב שהדרך שבה אנחנו משיגים את הType היא לא מדויקת, כיוון שצריך גם לציין את הNamespace (ולעתים גם את הAssemblyQualifiedName).)
נוכל גם ליצור instance של טיפוס שמקבל בConstructor שלו פרמטרים, למשל:
השורה הבאה:
|
|
מבצעת בסופו של דבר קריאה לConstructor כמו השורה הזאת:
|
|
הדבר ממש מגניב, אבל לכל דבר יש מחיר.
המחיר כאן הוא בביצועים – יצירת אובייקט בצורה דינמית באמצעות הפונקציהActivator.CreateInstance מוסיף מספר מילישניות לזמן שלוקח ליצור את האובייקט. זה די הרבה באופן יחסי, מאחר והCLR מאוד מהיר ביצירת אובייקטים (קריאה רגילה לnew לוקחת בערך 10 נאנו שניות).
כך שאם האפליקציה שלכם צריכה להתמודד עם קצבים מהירים, השימוש הנ"ל יכול להזיק לה.
נראה בעתיד דרכים יותר יעילות לעשות דברים דומים..
המשך יום טיפוסי