【问题标题】:How to create a custom Powershell operator?如何创建自定义 Powershell 运算符?
【发布时间】:2015-04-20 20:32:39
【问题描述】:

是否可以在 Powershell 中创建自定义运算符?而且,我该怎么做?我已经在 Google 上搜索过,但什么都没有。

我指的是一个中缀运算符:

$ExampleList -包含“元素”

我已经创建了 cmdlet(使用 Powershell 和 C#)、模块等,所以我只需要粗略的介绍。

【问题讨论】:

    标签: powershell customization


    【解决方案1】:

    您可以创建前缀运算符,但不能创建中缀或后缀运算符,例如:

    Set-Alias ?: Invoke-Ternary
    function Invoke-Ternary {
    param(
        [Parameter(Mandatory, Position=0)]
        [scriptblock]
        $Condition,
    
        [Parameter(Mandatory, Position=1)]
        [scriptblock]
        $TrueBlock,
    
        [Parameter(Mandatory, Position=2)]
        [scriptblock]
        $FalseBlock,
    
        [Parameter(ValueFromPipeline, ParameterSetName='InputObject')]
        [psobject]
        $InputObject
    )
    
    Process {
        if ($pscmdlet.ParameterSetName -eq 'InputObject') {
            Foreach-Object $Condition -input $InputObject | Foreach {
                if ($_) {
                    Foreach-Object $TrueBlock -InputObject $InputObject
                }
                else {
                    Foreach-Object $FalseBlock -InputObject $InputObject
                }
            }
        }
        elseif (&$Condition) {
            &$TrueBlock
        }
        else {
            &$FalseBlock
        }
    }
    

    这样使用:

    $toolPath = ?: {[IntPtr]::Size -eq 4} {"$env:ProgramFiles(x86)\Tools"} {"$env:ProgramFiles\Tools"}}
    

    【讨论】:

      【解决方案2】:

      想了想,我的想法是这样的:

      不确定这是否比 Jon Tirjan 的答案更好

      function Op {
          Param (
              # this operator is the reverse of -contains
              [switch] $isIn,
      
              # this operator is just an example 
              [switch] $Plus
          )
      
          if ($isIn) {
              if ($args.Length -ne 2) {
                  throw "Requires two arguments"
              }
      
              return ($args[1] -contains $args[0])
          }
          elseif ($Plus) {
              if ($args.Length -ne 2) {
                  throw "Requires two arguments"
              }
      
              return ($args[0] + $args[1])
          }
      }
      

      示例用法:

      PS> $ExampleList = @("alpha", "bravo", "charlie")
      
      PS> Op "alpha" -isIn $ExampleList
      True
      
      PS> Op "delta" -isIn $ExampleList
      False
      
      PS> Write-Host ("Answer: " + (Op 5 -plus 7))
      Answer: 12
      

      【讨论】:

        【解决方案3】:

        我知道这对游戏来说真的很晚了.. 但我想我会提供一个讨厌的 hack 替代方案.. 唯一的好处是制作一些“看起来”类似于 C# 运算符的东西。

            Set-Alias ?: Invoke-Ternary
            Function Invoke-Ternary {
              [cmdletbinding()]
              param(
                [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
                [object]$Condition,
                [Parameter(Mandatory=$true, Position=0)]
                [Alias('FirstExpression')]
                [object]$Consequent,
                [Parameter(Mandatory=$true, Position=1)]
                [Alias('SecondExpression')]
                [object]$Alternative
              )
              $isTrue = if($Condition.GetType().Name -eq 'Scriptblock'){ 
                Invoke-Command -ScriptBlock $Condition 
              } else { 
                $Condition 
              }
              if ($isTrue) {
                if($Consequent.GetType().Name -eq 'Scriptblock'){
                  Invoke-Command -ScriptBlock $Consequent
                } else {
                  $Consequent
                }
              } else { 
                if($Alternative.GetType().Name -eq 'Scriptblock'){
                  Invoke-Command -ScriptBlock $Alternative
                } else {
                  $Alternative
                }
              }
            }
            {[IntPtr]::Size -eq 4} |?: 'I like Soup' {'test'|?: 3  ('{0} prefer toast' -f 'We')}
            {[IntPtr]::Size -eq 8} |?: 'I like Soup' {$false|?: 3  ('{0} prefer toast' -f 'We')}
        

        虽然这实际上只不过是对用分号分隔的第一个表达式进行字符串修改(支持冒号),但它说明有多种方法可以完成此行为。 说了这么多..我很想创建官方运营商 三元和 Null-Coalescing 运算符.. 虽然我在这.. 一个官方的 Use-Object(使用语句(不是指令))也会很好。在那之前,我将继续我的小技巧,但梦想是美好的。

        【讨论】:

        • 使用编辑器的“代码”功能有助于提高答案的可读性,该功能会将您的整个代码段作为单个代码块,而不是仅对每一行进行反引号。
        • @ProgrammerDan 我对其进行了编辑。现在正在排队中
        • 虽然我喜欢拆分字符串的想法,但使用正则表达式评估表达式会很快变得混乱。例如,如果您的表达式包含字符串格式怎么办?但是,您是对的,我没有在前面的代码中正确评估 Condition。查看更新。
        【解决方案4】:

        您可以创建一个 cmdlet 并将列表通过管道传输到其中。 要评估列表,请务必使用 End 函数而不是 ProcessProcess 会自动迭代集合,这里你不需要。

        您的脚本将如下所示:

        $ExampleList | Test-Contains "element"
        

        【讨论】:

        • 这很好,管道让每个 cmdlet 都成为中缀运算符
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-10
        • 1970-01-01
        • 2015-07-26
        • 2022-07-06
        • 2023-01-15
        • 1970-01-01
        • 2014-08-21
        相关资源
        最近更新 更多