ประเภท. NET ในคลาส PowerShell

Oct 23 2020

ฉันพยายามทำความเข้าใจกับแนวทางปฏิบัติที่ดีที่สุดของ 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]และนี่คือข้อบกพร่องหรือคุณสมบัติ? และมีประเภทอื่นที่มีพฤติกรรมคล้ายกันหรือไม่?

คำตอบ

4 MathiasR.Jessen Oct 22 2020 at 22:44

นี่คือสภาพการแข่งขันเป็นหลัก!

เมื่อ 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อาร์กิวเมนต์พารามิเตอร์ได้เนื่องจากไม่มีประเภท