【发布时间】:2015-04-20 20:32:39
【问题描述】:
是否可以在 Powershell 中创建自定义运算符?而且,我该怎么做?我已经在 Google 上搜索过,但什么都没有。
我指的是一个中缀运算符:
$ExampleList -包含“元素”
我已经创建了 cmdlet(使用 Powershell 和 C#)、模块等,所以我只需要粗略的介绍。
【问题讨论】:
是否可以在 Powershell 中创建自定义运算符?而且,我该怎么做?我已经在 Google 上搜索过,但什么都没有。
我指的是一个中缀运算符:
$ExampleList -包含“元素”
我已经创建了 cmdlet(使用 Powershell 和 C#)、模块等,所以我只需要粗略的介绍。
【问题讨论】:
您可以创建前缀运算符,但不能创建中缀或后缀运算符,例如:
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"}}
【讨论】:
想了想,我的想法是这样的:
不确定这是否比 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
【讨论】:
我知道这对游戏来说真的很晚了.. 但我想我会提供一个讨厌的 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(使用语句(不是指令))也会很好。在那之前,我将继续我的小技巧,但梦想是美好的。
【讨论】:
您可以创建一个 cmdlet 并将列表通过管道传输到其中。
要评估列表,请务必使用 End 函数而不是 Process。
Process 会自动迭代集合,这里你不需要。
您的脚本将如下所示:
$ExampleList | Test-Contains "element"
【讨论】: