מחלקות PowerShell: התחלה

PowerShell הוא שפת תכנות מבוססת אובייקטים. כאשר אתה מפעיל פקודות, אתה רואה את הפלט על המסך שלך, ואלו הם אובייקטים. אובייקטים לא נוצרים משום מקום; מפתחים יוצרים אותם, או, להיות יותר מדויקים, מ實例צמצאים אותם עם קבוצות. קבוצות PowerShell מייצגות הגדרות או סכמות של אובייקטים.

אף שיכול להיות שאתה מכיר את יצירת האובייקטים עם פקודות כמו New-Object ושימוש באקסלרטור סוג pscustomobject, אלו אינם אובייקטים "חדשים". סוגי האובייקטים שאלו השיטות יוצרות הם מסוג מסוים type. קבוצות PowerShell מגדירות את ה type.

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

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

דרישות קדם

יצירת הקבוצה והאובייקט הראשונים שלך

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

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

מטה תראה את גוף המחלקה הריק של תלמיד.

class student {

}

מחלקות מכילות מאפיינים שנראים כמו פרמטרים שהם אטריביוטים שמתארים את המחלקה ההוא. הדוגמה מתחת מראה מחלקה בשם תלמיד עם שני מאפיינים; שם_פרטי ו־שם_משפחה.

כאשר אתה מגדיר מאפיין, תמיד עליך להגדיר סוג שמגדיר "סכימה" מסוימת למה שערכי המאפיין יכולים להכיל. בדוגמה מתחת, שני המאפיינים מוגדרים כמחרוזות.

תמיד עליך להגדיר סוגי מאפיין. תראה מאוחר יותר למה.

class student {
    [string]$FirstName
    [string]$LastName
}

לאחר שאתה מגדיר מחלקה, צור אובייקט ממנה או הפעל אובייקט. ישנם דרכים מרובות ליצירת אובייקטים ממחלקות; דרך אחת נפוצה היא להשתמש באצלרטורים סוג כמו [תלמיד] שמייצגים את המחלקה, אחריהם מתבצעת פעולת ברירת המחדל הקיימת עם כל מחלקה בשם חדש().

שימוש בקיצור דרך של אצלרטור הוא זהה ליצירת אובייקט באמצעות פקודת New-Object.

New-Object -TypeName student

פעם שיצרת אובייקט מהמחלקה ההזאת, הקצה ערכים לתכונות. הדוגמה למטה מקצה ערכים של Tyler ו־Muir לתכונות FirstName ו־LastName.

class student {
    [string]$FirstName
    [string]$LastName
}
$student1 = [student]::new()
$student1.FirstName = 'Tyler'
$student1.LastName = 'Muir'
$student1

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

Creating an object from the student class.

עכשיו שיצרת אובייקט ממחלקה, הפוך את האובייקט הזה כמו כל אובייקט אחר ב־PowerShell ל־Get-Member cmdlet כדי לבדוק אותו. ניתן לראות מטה שהאובייקט שמאחסן בתוך המשתנה $student1 הוא מסוג student.

שם המחלקה תמיד יתאים לסוג האובייקט.

שים לב ש־Get-Member מחזיר ארבעה שיטות ושתי תכונות. התכונות כנראה מוכרות, אבל השיטות בוודאי לא. PowerShell מוסיף שיטות מסוימות ברירת מחדל, אך אפשר להוסיף שיטות משלך או אפילו לשנות את השיטות הברירת מחדל.

Showing members from custom student object.

יצירת שיטות

בדוגמה למעלה, ראית כמה שיטות ברירת מחדל על האובייקט, אך סיכוי גדול שתרצה ליצור שלך. כדי לעשות זאת, עליך להגדיר שיטה או יותר בתוך ההגדרה של המחלקה.

A method definition looks like below with an output type that defines what type of object is returned from this method, the name of the method, and the code to execute inside of a scriptblock.

[<output type>]<name>() {
	<code that runs when the method is executed>
}

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

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

return הוא חובה

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

function foo {
	$object = Get-Service
	$object ## פשוט שולחים את העצם לצינור
}

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

[string]GetName() {
	return 'foo'
}

שימוש במשתנה $this

ההבדל הבא שיש לשיטות ביחס לפונקציות הוא המשתנה $this. המשתנה $this, כפי שמוגדר בתוך שיטה, מפנה למאפייני האובייקט הנוכחי או לשיטות אחרות.

למטה דוגמה לשיטה בשם GetName() הנוספת למחלקת student שמחברת את ערכי המאפיינים FirstName ו־LastName ומחזירה אותם.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
}

עכשיו אתה יכול לקרוא לשיטה GetName() באמצעות הסימון בנקודה כפי שמוצג למטה. אם קודם כבר השמת ערכים למאפיינים FirstName ו־LastName, GetName() תחזיר אותם.

Creating a class with a method and showing to output.

הוספת פרמטרים ל־שיטות

בדוגמה למעלה, כאשר הרצת את השורה $student1.GetName(), אתה קורא לשיטה GetName() כפי שהיא. בתוך הסוגריים, ניתן להגדיר פרמטרים כמו בפונקציות.

השיטה GetName() פשוטה החזירה את הערכים שהוגדרו עבור מאפייני FirstName ו-LastName. אך מה קורה אם תרצה ליצור שיטה שתוכל להגדיר ערכים עבור המאפיינים ש-GetName() תוכל לקבל? במקרה כזה, יש לך צורך להגדיר פרמטרים לשיטה.

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

שים לב לסוג הפלט [void]. כל פעם ששיטה אינה מחזירה דבר, לא נדרש קונסטרוקטור return, ועליך להגדיר את סוג הפלט כ-[void] כדי להגיד לפוורשל שהשיטה אינה מחזירה דבר.

[void]SetName([string]$Name) {

}

לדוג, אולי שיטת SetName() מקבלת שם מלא (שם פרטי ושם משפחה). אם זו המקרה, בבלוק הקוד, תוכל לפצל את המחרוזת ולהקצות את השם הפרטי והשם המשפחתי בדרך זו.

על ידי הכנסת שיטת SetName() לתוך מחלקת student, כך נראה הקוד כעת.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

כעת תוכל להעביר שם מלא כפרמטר לשיטה SetName(), שמגדירה את מאפייני FirstName ו-LastName של אובייקט הנוכחי.

Creating a class with a void method and showing the output when it is run.

עודפון שיטות

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

אולי תרצה להגדיר את הפרמטרים FirstName ו־LastName על ידי מעבר של שם מלא ל־SetName() שיטה או במעבר של שם פרטי ושם משפחה בנפרד. אין צורך לבחור; תוכל להגדיר אותם שניהם עם חתימות השיטות.

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

כאשר אתה משתמש בדוגמה מהסעיף הקודם, תוכל ליצור העמסה עבור שיטת SetName() כדי לקבל שני מחרוזות במקום אחת. כאשר אתה מעביר שתי מחרוזות במקום אחת, השיטה SetName() מניחה שהמחרוזת הראשונה היא ה־FirstName והמחרוזת השנייה היא ה־LastName. עם העמסה זו, המחלקה תיראה כמו בתמונה למטה.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
    
    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}
Showing that the method overload works by providing either one or two strings.

בוני מחלקה

כל פעם שאתה מפעיל אובייקט עם שיטת new() או בדרך אחרת, אתה יכול להגיד לפוורשל להפעיל קוד מוגדר על ידי משתמש נקרא בונה. בונים הם דומים לשיטות, אך הם מופעלים אוטומטית כאשר פוורשל מפעיל אובייקט.

לכל מחלקה יש בונה ברירת מחדל. הבונה ברירת המחדל הזו לא עושה הרבה; היא פשוטה אחראית על ליצור את האובייקט. תוכל לראות את בונת ברירת המחדל על ידי הצגת פלט של שיטת New. תוכל לראות למטה שהשורה הזו מחזירה את שיטת new() יחידה.

[student]::New
Default PowerShell constructor

העמסת בונים

אולי תרצה להגדיר ערך עבור התכונות FirstName ו-LastName ברגע שאתה יוצר את האובייקט, לא עם הנוטציה הנקודתית הטיפוסית. במקרה כזה, אתה יכול ליצור בנאי עם פרמטר שאז קורא ל-SetName().

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

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

student([string]$Name) {
	$this.SetName($Name)
}

ולהלן תראה שהבנאי הוסף לכיתה student.

class student {
    [string]$FirstName
    [string]$LastName
    
    student([string]$Name) {
        $this.SetName($Name)
    }

    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

כאשר אתה מייצג אובייקט student חדש ומעביר פרמטר מחרוזת, תכונות האובייקט יהיו מיד עם הערכים הצפויים.

Showing the output from using the constructor with a string

עכשיו תוכל לראות שוב את הבנאי המעמיס עם [student]::New. שים לב כעת שהבנאי המעמיס החדש הוגדר עם פרמטר Name.

Overloaded constructor

הגדרת בנאי ברירת מחדל ומעמיס

עכשיו, לאחר שיש לך בנאי מעמיס על הכיתה student, PowerShell מחליף את בנאי ברירת המחדל. אבל, אתה יכול להחזיר אותו על ידי יצירה ידנית של אחד ללא פרמטרים.

student() {}

תוכל לראות איך זה נראה בכיתה student למטה.

class student {
    [string]$FirstName
    [string]$LastName

    student([string]$Name) {
        $this.SetName($Name)
    }

    student() {}

    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

עכשיו בדוק שוב את הבנאים. תראה כעת ששני הבנאים מופיעים.

[student]::New
Creating a default and custom constructor

ירושת מחלקות

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

לדוגמה, מחלקת ה-student שלנו מייצגת סטודנט באוניברסיטה (ילד/ספציפית). סטודנט זה הוא אדם (הורה/כללית). שני הקונספטים הללו קשורים ויוצרים היררכיה.

A child class can inherit a parent class which means it can hold all properties and methods (members) defined via a parent class. We know that a person class may have properties like eye_color, height, and weight and perhaps a method called SetHeight().

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

אם זה לא מובן כעת, זה יתבהר בהמשך כשנעבור על דמו.

דמו לירושת מחלקה

ראשית, צור העתק של מחלקת ה-student שיצרת לך לפני כן, הסר את הבנאי ושנה את שמו למחלקת person. מחלקת person שלך צריכה להיראות כמו המחלקה למטה.

A student, of course, has a first name and last name, but the class can be described more accurately by labeling it as a person. When creating a more “generic” class like this, you can create more specific “child” classes from it.

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

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

class teacher {
    [int]$EmployeeId
}

class student {
    [int]$StudentId
}

כפי שהן נמצאות כעת, מחלקות teacher ו-student הן יחסית זרות ממחלקת person. הן אין להן קשר אך אין להן את היכולת לירוש מחברי המחלקה של מחלקת person. בוא נשנה זאת.

עכשיו הגדר את ההיררכיה הזו על ידי הגדרת מחלקת teacher ומחלקת student כ"מחלקות ילד" של מחלקת person עם ירושה. תוכל להגדיר ירושה על ידי הוספת נקודתיים (:) אחרי שם המחלקה ואז שם המחלקה האב כמו שמוצג למטה.

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

הסקריפט של כל המחלקות שלך צריך להיראות כעת כך:

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

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

Class Inheritance Demo

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

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

לדוגמה, אולי רק הגדרת בנאי עמוס עבור מחלקת person אך לא הגדרת בנאי עבור מחלקת teacher, כמו שמוצג למטה.

class person {
    [string]hidden $FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }

		person([string]$Name) {
			$this.SetName($Name)
		}
}

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

No class defined for child class

A constructor is not necessary in a child class if you’re only using it as a template. Alternatively, if you want to use the parent class as its own standalone class and as a parent class you can include constructors. But you have to make sure that the parent class has a constructor that matches the ones in the child classes.

מאפייני חברי המחלקה

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

חברים מוסתרים

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

כדי להגדיר חבר מוסתר, יש להשתמש במאפיין hidden כפי שמוצג למטה.

class teacher {
    [int]hidden $EmployeeId
}

עכשיו כשאתה משתמש ב-Get-Member כדי לבדוק את כל חברי האובייקט, המאפיין הזה לא מופיע.

Class Member Attributes

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

חברים סטטיים

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

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

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

class student {
	[int]static $MaxClassCount = 7
}

בניגוד לחברי מחלקה טיפוליים, PowerShell לא יוצרת מאפיינים ושיטות מחברי מחלקה סטטיים. כאשר אתה מגדיר חבר מחלקה כסטטי, כמו חברים מוסתרים, הם לא מופיעים כשאתה משתמש ב-Get-Member.

Static Members

לדוג, אולי תרצה לשייך שמות של קורסים באוניברסיטה למחלקה student ולהגדיר את מספר הקורסים המרבי שסטודנט יכול להשתתף בהם. כדי לעשות זאת, יש ליצור חבר מערך Classes וחבר MaxClassCount.

מכיוון שלרוב המשתמש ידרוש לשנות בנדיבות את חבר MaxClassCount, נבחר להגדיר אותו כסטטי.

לבסוף, ניצור שיטת AddClass() כדי להוסיף קורס ללוח הזמנים של הסטודנט, אך רק אם הוא פחות מ- MaxClassCount.

class student {
    [string[]]$Classes = @()
    [int]static $MaxClassCount = 7
    
    [void]AddClass ([string]$Name) {
        if ($this.Classes.Count -lt [student]::MaxClassCount) {
            $this.Classes += $Name
        }
    }
}

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

$student1 = [student]::new()
'PE','English','Math','History','Computer Science','French','Wood Working','Cooking' | ForEach-Object {
	$student1.AddClass($_)
}
$student1.Classes
Class Count

אפשר לשנות ערכי חברים סטטיים בכל עת. לדוג, אם תרצה להגדיר את ערך חבר MaxClassCount להיות 5 במקום 7, תשנה את הערך באמצעות [student]::MaxClassCount = 5. שינוי הערך לא יסיר באופן חוזר את הקורסים שחורגים מהמגבלה בדוגמה זו.

סיכום

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

Source:
https://adamtheautomator.com/powershell-classes/