2016-06-08 105 views
2

(PowerShell的5)
我有以下COALESCE函數:您可以將CmdletBinding與未綁定參數結合使用嗎?

更新:刪除在process塊中的 「優化」 continue調用)

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; 

您可能會注意到t我把決策邏輯封裝在一個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,如果可能的話)。這樣我可以有合併以及一般的算法:

$Test = { -not [string]::IsNullOrEmpty([string]$_) }; 
$NULL,$NULL,'','' | Find-Defined -Test $Test $NULL,'','This should be it' 'Not seen' 

我缺少的東西?

+1

順便提一下,'continue'是循環控制指令。很可能,當你將你的函數放在腳本中時,它對你來說意想不到。 – PetSerAl

+0

@PetSerAl:你說得對。在原版中,我添加了一些其他步驟 - 就像沒有在'begin'塊中指定的'ScriptBlock'一樣。我會改回它。 – Axeman

回答

1

我相信這解決了您正在嘗試解決的問題,但有一些不同的實現。當使用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; 
     } 
    } 
} 
相關問題