ประเภท. NET ในคลาส PowerShell
ฉันพยายามทำความเข้าใจกับแนวทางปฏิบัติที่ดีที่สุดของ PowerShell Class และพบกับความสับสนกับคลาสง่ายๆในการจัดการ Balloon Tips
Add-Type -assemblyName:System.Drawing
Add-Type -assemblyName:System.Windows.Forms
class PxMessage {
static [PxMessage] $instance static $balloon
static $defaultIcon static [PxMessage] GetInstance($processIcon) {
if ([PxMessage]::instance -eq $null) { [PxMessage]::instance = [PxMessage]::new() #[PxMessage]::balloon = [Windows.Forms.NotifyIcon]::new() [PxMessage]::balloon = New-Object Windows.Forms.NotifyIcon [PxMessage]::defaultIcon = $processIcon
}
return [PxMessage]::instance
}
[Void] SendMessage ([String]$title, [String]$message, [String]$messageIcon) { [PxMessage]::balloon.icon = [PxMessage]::defaultIcon [PxMessage]::balloon.balloonTipTitle = $title
[PxMessage]::balloon.balloonTipText = $message [PxMessage]::balloon.balloonTipIcon = $messageIcon
[PxMessage]::balloon.visible = $true [PxMessage]::balloon.ShowBalloonTip(0) [PxMessage]::balloon.Dispose } } $processIcon = [System.Drawing.Icon]::ExtractAssociatedIcon($(Get-Process -id:$PID | Select-Object -expandProperty:path))
$message = [PxMessage]::GetInstance($processIcon)
$message.SendMessage('Title', "$(Get-Date)", 'Info')
ฉันมีคำถามสองข้อ:
1: ทำไมใช้[PxMessage]::balloon = New-Object Windows.Forms.NotifyIconงานได้ แต่[PxMessage]::balloon = [Windows.Forms.NotifyIcon]::new()ไม่ทำงาน ( Unable to find typeerror)? และนี่เป็นการแนะนำว่าการใช้[Type]::new()ยังไม่ได้รับการสนับสนุนอย่างเต็มที่และเพื่อความสอดคล้องฉันควรใช้ New-Object ทุกที่ดีกว่าไหม หรืออย่างน้อยก็ทุกที่ในชั้นเรียนของฉันเอง?
2: ฉันต้องการพิมพ์คุณสมบัติและพารามิเตอร์ของฉัน แต่ฉันยังได้รับUnable to find typeข้อผิดพลาดเมื่อฉันพิมพ์$balloon& $defaultIconคุณสมบัติหรือถ้าฉันพิมพ์$processIconพารามิเตอร์ในGetInstanceวิธีการ
เห็นได้ชัดว่าฉันสามารถพิมพ์ Properties ได้แม้ว่าจะมีการกำหนดประเภทของฉันก็ตาม แล้วสิ่งที่แตกต่างกันเกี่ยวกับสอง[System.Drawing]& [System.Windows.Forms]และนี่คือข้อบกพร่องหรือคุณสมบัติ? และมีประเภทอื่นที่มีพฤติกรรมคล้ายกันหรือไม่?
คำตอบ
นี่คือสภาพการแข่งขันเป็นหลัก!
เมื่อ PowerShell เริ่มเรียกใช้ไฟล์สคริปต์จะดำเนินการ 3 ขั้นตอน:
- การแยกวิเคราะห์
- การรวบรวม
- การดำเนินการ
สิ่งแรกที่มีการประมวลผลในการรวบรวมเฟส (ดังนั้นก่อนที่จะดำเนินการแม้เริ่มต้น) เป็น:
usingข้อความทั้งหมดที่ด้านบนของสคริปต์- คำจำกัดความประเภทใด ๆ - ใด ๆ
classหรือenumคำหลัก - จะถูกรวบรวมแยกกัน
ดังนั้นข้อผิดพลาดที่เกี่ยวข้องกับการแก้ไข[Windows.Forms.NotifyIcon]ประเภทลิเทอรัลภายในนิยามคลาสจึงเกิดขึ้นจริงก่อนที่ Add-Type -AssemblyName:System.Windows.Formsจะมีโอกาสรัน!
สองตัวเลือก:
สคริปต์ที่ซ้อนกัน
เขียนสคริปต์ตัวโหลดแยกต่างหากที่โหลดการอ้างอิง:
# loader.ps1
Add-Type -AssemblyName System.Windows.Forms,System.Drawing
. .\scriptWithTypes.ps1
# scriptWithTypes.ps1
class ClassDependentOnForms
{
[Windows.Forms.NotifyIcon]$BalloonTipIcon
}
ด้วยโมดูล
ด้วยโมดูลมันง่ายกว่าเล็กน้อยในการจัดการการอ้างอิงก่อนการคอมไพล์นิยามประเภทที่กำหนดเอง - เพียงแค่เพิ่มชื่อแอสเซมบลีตามRequiredAssembliesรายการโมดูล:
New-ModuleManifest ... -RootModule moduleWithTypes.psm1 -RequiredAssemblies System.Windows.Forms,System.Drawing
โหลดจากดิสก์ด้วย using assembly ...
หากทราบเส้นทางของแอสเซมบลีที่ต้องการคุณสามารถโหลดได้ในเวลาแยกวิเคราะห์ด้วยusing assemblyคำสั่ง:
using assembly '.\path\to\System.Drawing.dll'
using assembly '.\path\to\System.Windows.Forms.dll'
class FormsDependentClass
{
[Windows.Forms.NotifyIcon]$BallonTipIcon
}
สำหรับกรณีการใช้งานของคุณอันสุดท้ายนี้ไม่น่าสนใจเท่าไหร่เพราะคุณต้องฮาร์ดโค้ดแอสเซมบลีแทนที่จะโหลดจาก GAC ตามชื่อ
เหตุใดจึงเกิดขึ้นตั้งแต่แรก
พฤติกรรมนี้อาจทำให้สับสนเล็กน้อยเนื่องจากสิ่งอื่น ๆใน PowerShell เป็นเพียงการตีความ "ทีละคำสั่ง" ที่ตรงไปตรงมา
เหตุผลสำหรับข้อยกเว้นนี้คืออนุญาตให้สคริปต์และฟังก์ชันห่อหุ้มประเภทพารามิเตอร์ที่กำหนดเอง:
param(
[CustomEnumType]$Option ) begin { enum CustomEnumType { None Option1 Option2 } } end { # do something based on $Option
}
หากไม่มีการคอมไพล์ล่วงหน้าCustomEnumTypeในเวลาแยกวิเคราะห์ PowerShell จะไม่สามารถเสนอการเติมข้อความอัตโนมัติและการตรวจสอบอินพุตสำหรับ-Optionอาร์กิวเมนต์พารามิเตอร์ได้เนื่องจากไม่มีประเภท