PowerShell类中的.NET类型 [英] .NET types in PowerShell classes

查看:49
本文介绍了PowerShell类中的.NET类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在设法了解PowerShell类的最佳实践,并与处理气球提示的简单类陷入困惑.

I am trying to get my head around PowerShell Class best practices, and running into some confusion with a simple class to handle 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 =新对象Windows.Forms.NotifyIcon 起作用,但是 [PxMessage] :: balloon = [Windows.Forms.NotifyIcon]::new()不会(找不到类型错误)?这是否表明尚未完全支持使用 [Type] :: new(),并且为了保持一致性,我最好在任何地方都使用New-Object吗?还是至少在我自己的班级的任何地方?

1: Why does [PxMessage]::balloon = New-Object Windows.Forms.NotifyIcon work, but [PxMessage]::balloon = [Windows.Forms.NotifyIcon]::new() does not (Unable to find type error)? And does this suggest that using [Type]::new() is not yet fully supported, and for consistency sake I am better off using New-Object everywhere? Or at least everywhere in my own Classes?

2:我想输入我的属性&参数,但是当我键入 $ balloon &时,也会出现无法找到类型错误. $ defaultIcon 属性,或者如果我在 GetInstance 方法中键入 $ processIcon 参数.

2: I would like to type my properties & parameters, but I also get Unable to find type errors when I type the $balloon & $defaultIcon properties, or if I type the $processIcon parameter in the GetInstance method.

很明显,即使定义了我的类型,我也可以键入Properties.那么这两个 [System.Drawing] &有什么不同? [System.Windows.Forms] ,这是错误还是功能?还有其他类似的类型吗?

Obviously I can type Properties, even with my type being defined. So what is different about the two [System.Drawing] & [System.Windows.Forms], and is this a bug, or a feature? And are there other types that behave similarly?

推荐答案

这本质上是一种竞争条件!

This is essentially a race condition!

PowerShell开始执行脚本文件时,将经历三个阶段:

When PowerShell starts executing a script file, it goes through 3 phases:

  • 解析
  • 编译
  • 执行

compilation 阶段处理的第一件事(因此,甚至在之前开始执行)是:

The very first thing that is processed in the compilation phase, (so before execution even begins) is:

    脚本顶部的
  • 所有 using 语句
  • 任何类型定义-任何 class enum 关键字-均需单独编译
  • All using statements at top of the script
  • Any type definitions - any class or enum keywords - are compiled separately

因此,与解析类定义中的 [Windows.Forms.NotifyIcon] 类型文字相关的错误实际上是在之前 Add-Type -AssemblyName抛出的:System.Windows.Forms 有机会运行!

So the errors related to resolving the [Windows.Forms.NotifyIcon] type literal inside the class definition are actually thrown before Add-Type -AssemblyName:System.Windows.Forms gets a chance to ever run!

选项对:

编写一个单独的加载程序脚本来加载依赖项:

Write a separate loader script that loads the dependency:

# loader.ps1
Add-Type -AssemblyName System.Windows.Forms,System.Drawing
. .\scriptWithTypes.ps1

# scriptWithTypes.ps1
class ClassDependentOnForms
{
  [Windows.Forms.NotifyIcon]$BalloonTipIcon
}

带有模块

使用模块,在编译自定义类型定义之前管理依赖项会更简单-只需将程序集名称作为 RequiredAssemblies 添加到模块清单中即可:

With modules

With modules it's a bit simpler to manage dependencies ahead of compiling the custom type definitions - just add the assembly names as RequiredAssemblies to the module manifest:

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

使用程序集使用从磁盘加载...

如果所需程序集的路径是已知的,则可以在解析时使用 using assembly 语句加载它:

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

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

对于您的用例来说,最后一个不是很吸引人,因为您需要对程序集进行硬编码,而不是仅按名称从GAC加载程序集.

For your use case, this last one is not very attractive because you'd need to hardcode the assembly instead of just loading it from the GAC by name.

此行为可能会造成一些混乱,因为PowerShell中的其他所有内容都是一次一个语句"的简单解释.

This behavior might be slightly confusing because everything else in PowerShell is just straightforward "one statement at a time"-interpretation.

此异常的原因是允许脚本和函数封装自定义参数类型:

The reason for this exception is to allow scripts and functions to encapsulate custom parameter types:

param(
  [CustomEnumType]$Option
)

begin {
  enum CustomEnumType {
    None
    Option1
    Option2
  }
}

end {
  # do something based on $Option
}

如果在解析时没有先行编译 CustomEnumType ,PowerShell将无法为 -Option 参数自变量提供自动补全和输入验证-因为它的类型将不存在

Without this preemptive compilation of CustomEnumType at parse time, PowerShell would be unable to offer autocompletion and input validation for the -Option parameter argument - because it's type would not exist

这篇关于PowerShell类中的.NET类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆