2016-06-08 3 views
2

(Powershell 5)
У меня есть следующие Coalesce функции:Можете ли вы объединить CmdletBinding с несвязанными параметрами?

(UPDATE:. Убрано "оптимизированный" 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; 

Вы можете заметить, что 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

BTW, 'continue' является инструкцией по управлению циклом. Очень вероятно, что он будет вести себя непредсказуемо для вас, когда вы поместите свою функцию в скрипт. – PetSerAl

+0

@PetSerAl: Вы правы.В обезьянье с оригиналом я добавил несколько других шагов - как будто не было 'ScriptBlock', указанного в блоке' begin'. Я изменю его. – 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; 
     } 
    } 
} 
Смежные вопросы