(Powershell 5)
我有以下合并功能:
(更新:删除了continue
块中"优化" process
来电。
function Find-Defined {
begin {
$ans = $NULL;
$Test = { $_ -ne $NULL };
}
process {
if ( $ans -eq $NULL ) {
$ans = $_ |? $Test | Select -First 1;
}
}
end {
if ( $ans -ne $NULL ) {
return $ans;
}
else {
$Args `
|% { if ( $_ -is [Array] ) { $_ |% { $_ } } else { $_ } } `
|? $Test `
| Select -First 1 `
| Write-Output `
;
}
}
}
这对我来说很有用,在以下命令行上:
$NULL, $NULL, 'Legit', 1, 4 | Find-Defined;
$NULL, $NULL | Find-Defined $NULL, @( $NULL, 'Value' ), 3;
$NULL, $NULL | Find-Defined $NULL $NULL 3 4;
您可能会注意到我将决策逻辑封装在ScriptBlock
变量中。这是因为我想参数化它,我开始尝试这个。
[CmdletBinding()]param( [ScriptBlock] $Test = { $_ -ne $NULL } );
然而,在我添加CmdletBinding
的那一刻,我开始出错。绑定想要尝试将参数部分中的所有内容都转换为ScriptBlock
,所以我添加了
[CmdletBinding(PositionalBinding=$False)]
然后它抱怨未绑定的论点无法绑定,所以我补充说:
param( [parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)][Object[]] $Arguments ...
无论我做了什么事后都添加了一个新的错误。如果我删除了$Test
参数,只是将其本地化以查看我能做什么,那么我开始得到开发第一代时的错误:
The input object cannot be bound to any parameters for the command either
because the command does not take pipeline input or the input and its
properties do not match any of the parameters that take pipeline input.
...即使我有一个process
块。
最后只需删除param
语句,将其恢复为我喜欢的灵活功能。
我仍然希望扩展此功能以接受ScriptBlock
测试和未绑定参数(以及-Verbose
等公共参数,如果这样做的话可能)。这样我就可以有 string 合并的通用算法:
$Test = { -not [string]::IsNullOrEmpty( [string]$_ ) };
$NULL,$NULL,'','' | Find-Defined -Test $Test $NULL,'','This should be it' 'Not seen'
我错过了什么吗?
答案 0 :(得分:2)
我相信这可以解决您尝试解决的问题,但有一些不同的实现。使用CmdletBinding
时,必须声明所有内容。因此,您需要一个参数用于管道输入,一个参数用于"未绑定"参数。
基于你的问题,我写了这些测试用例:
Describe 'Find-Defined' {
it 'should retun Legit' {
$NULL, $NULL, 'Legit', 1, 4 | Find-Defined | should be 'Legit'
}
it 'should retun Value' {
$NULL, $NULL | Find-Defined $NULL, @( $NULL, 'Value' ), 3 | should be 'Value'
}
it 'should retun 3' {
$NULL, $NULL | Find-Defined $NULL $NULL 3 4 | should be '3'
}
it 'Should return "This should be it"' {
$Test = { -not [string]::IsNullOrEmpty( [string]$_ ) };
$NULL,$NULL,'','' | Find-Defined -Test $Test $NULL,'','This should be it' 'Not seen' | should be 'This should be it'
}
}
这是我的解决方案,它通过了上述所有案例。
function Find-Defined {
[CmdletBinding()]
param (
[ScriptBlock] $Test = { $NULL -ne $_},
[parameter(Mandatory=$False,ValueFromPipeline =$true)]
[Object[]] $InputObject,
[parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)]
[Object[]] $Arguments
)
begin {
$ans = $NULL;
function Get-Value {
[CmdletBinding()]
param (
[ScriptBlock] $Test = { $_ -ne $NULL },
[parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)]
[Object[]] $Arguments,
$ans = $NULL
)
$returnValue = $ans
if($null -eq $returnValue)
{
foreach($Argument in $Arguments)
{
if($Argument -is [object[]])
{
$returnValue = Get-Value -Test $Test -Arguments $Argument -ans $returnValue
}
else
{
if ( $returnValue -eq $NULL ) {
$returnValue = $Argument |Where-Object $Test | Select-Object -First 1;
if($null -ne $returnValue)
{
return $returnValue
}
}
}
}
}
return $returnValue
}
}
process {
$ans = Get-Value -Test $Test -Arguments $InputObject -ans $ans
}
end {
$ans = Get-Value -Test $Test -Arguments $Arguments -ans $ans
if ( $ans -ne $NULL ) {
return $ans;
}
}
}