PowerShell sınıflarında .NET türleri

Oct 23 2020

PowerShell Sınıfı en iyi uygulamalarına kafa yormaya çalışıyorum ve Balon İpuçları ile başa çıkmak için basit bir sınıfla bazı karışıklıklarla karşılaşıyorum.

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')

İki sorum var:

1: Neden [PxMessage]::balloon = New-Object Windows.Forms.NotifyIconçalışıyor ama [PxMessage]::balloon = [Windows.Forms.NotifyIcon]::new()çalışmıyor ( Unable to find typehata)? Ve bu [Type]::new(), kullanımın henüz tam olarak desteklenmediğini ve tutarlılık adına New-Object'i her yerde kullanmamın daha iyi olduğunu gösteriyor mu? Ya da en azından kendi Sınıflarımdaki her yerde?

2: Özelliklerimi ve parametrelerimi yazmak istiyorum, ancak & özelliklerini yazdığımda veya parametreyi yöntemde yazdığımda da Unable to find typehata alıyorum .$balloon$defaultIcon$processIconGetInstance

Açıkçası, türüm tanımlanmış olsa bile Özellikler yazabilirim. Öyleyse ikisi [System.Drawing]& ile ilgili farklı olan nedir [System.Windows.Forms]ve bu bir hata mı yoksa özellik mi? Ve benzer şekilde davranan başka türler var mı?

Yanıtlar

4 MathiasR.Jessen Oct 22 2020 at 22:44

Bu esasen bir yarış durumu!

PowerShell bir betik dosyasını yürütmeye başladığında, 3 aşamadan geçer:

  • Ayrıştırma
  • Derleme
  • Yürütme

İlk şey olarak işlenir derleme aşamasında, (böylece önceki yürütme bile başlar) aşağıdaki gibidir:

  • usingKomut dosyasının üst kısmındaki tüm ifadeler
  • Herhangi bir tür tanımı - herhangi biri classveya enumanahtar sözcük - ayrı olarak derlenir

Dolayısıyla, [Windows.Forms.NotifyIcon]sınıf tanımının içindeki değişmez tipin çözümlenmesiyle ilgili hatalar , herhangi bir çalışma şansı yakalanmadan önce atılır Add-Type -AssemblyName:System.Windows.Forms!

Birkaç seçenek:

İç içe geçmiş komut dosyaları

Bağımlılığı yükleyen ayrı bir yükleyici komut dosyası yazın:

# loader.ps1
Add-Type -AssemblyName System.Windows.Forms,System.Drawing
. .\scriptWithTypes.ps1
# scriptWithTypes.ps1
class ClassDependentOnForms
{
  [Windows.Forms.NotifyIcon]$BalloonTipIcon
}

Modülleri ile

Modüllerle, özel tür tanımlarını derlemeden önce bağımlılıkları yönetmek biraz daha kolaydır - RequiredAssembliesmodül bildirimine göre montaj adlarını eklemeniz yeterlidir:

New-ModuleManifest ... -RootModule moduleWithTypes.psm1 -RequiredAssemblies System.Windows.Forms,System.Drawing

Diskten yükle using assembly ...

Gerekli derlemenin yolu biliniyorsa, onu ayrıştırma zamanında bir deyimle yükleyebilirsiniz using assembly:

using assembly '.\path\to\System.Drawing.dll'
using assembly '.\path\to\System.Windows.Forms.dll'

class FormsDependentClass
{
  [Windows.Forms.NotifyIcon]$BallonTipIcon
}

Kullanım durumunuz için, bu sonuncusu pek çekici değildir çünkü montajı GAC'den adıyla yüklemek yerine kodlamanız gerekir.


Bu neden ilk etapta oluyor?

Bu davranış biraz kafa karıştırıcı olabilir, çünkü PowerShell'deki diğer her şey basit "bir seferde bir ifade" yorumudur.

Bu istisnanın nedeni, komut dosyalarının ve işlevlerin özel parametre türlerini sarmalamasına izin vermektir:

param(
  [CustomEnumType]$Option ) begin { enum CustomEnumType { None Option1 Option2 } } end { # do something based on $Option
}

CustomEnumTypeAyrıştırma zamanında bu önleyici derleme olmadan , PowerShell -Optionparametre bağımsız değişkeni için otomatik tamamlama ve giriş doğrulaması sunamaz - çünkü türü mevcut olmaz