Подтвердить что ты не робот

Передать функцию в качестве параметра

Я написал функцию "А", которая будет вызывать одну из ряда других функций. Чтобы сохранить функцию перезаписи 'A', я бы хотел передать функцию, которая будет вызываться, как параметр функции 'A'. Например:

function A{
    Param($functionToCall)
    Write-Host "I'm calling : $functionToCall"
}

function B{
    Write-Host "Function B"
}

Function C{
    write-host "Function C"
}

A -functionToCall C

Возвращает: я звоню: C

Я ожидаю, что он вернется: Я звоню: функция C.

Я пробовал разные вещи, такие как:

Param([scriptblock]$functionToCall)

Не удается преобразовать System.String в ScriptBlock

A -functionToCall $function:C

Возвращает функцию записи-хоста C

A - functionToCall (&C)

Это оценивает перед остальным:

 Function C
 I'm Calling :

Я уверен, что это программирование 101, но я не могу определить правильный синтаксис или что я делаю неправильно.

4b9b3361

Ответ 1

Это то, что вам нужно?

function A{
    Param($functionToCall)
    Write-Host "I'm calling : $functionToCall"

    #access the function-object like this.. Ex. get the value of the StartPosition property
    (Get-Item "function:$functionToCall").ScriptBlock.StartPosition

}

function B{
    Write-Host "Function B"
}

Function C{
    write-host "Function C"
}


PS> a -functionToCall c

I'm calling : c


Content     : Function C{
                  write-host "Function C"
              }
Type        : Position
Start       : 307
Length      : 43
StartLine   : 14
StartColumn : 1
EndLine     : 16
EndColumn   : 2

Ответ 2

Я не уверен, что это лучше, но:

function A{
    Param([scriptblock]$FunctionToCall)
    Write-Host "I'm calling $($FunctionToCall.Invoke(4))"
}

function B($x){
    Write-Output "Function B with $x"
}

Function C{
    Param($x)
    Write-Output "Function C with $x"
}

PS C:\WINDOWS\system32> A -FunctionToCall $function:B
I'm calling Function B with 4

PS C:\WINDOWS\system32> A -FunctionToCall $function:C
I'm calling Function C with 4

PS C:\WINDOWS\system32> A -FunctionToCall { Param($x) "Got $x" }
I'm calling Got x

Ответ 3

Вы думали о передаче ScriptBlock в качестве параметра?

$scriptBlock = { Write-Host "This is a script block" }
Function f([ScriptBlock]$s) {
  Write-Host "Invoking ScriptBlock: "
  $s.Invoke()
}

PS C:\> f $scriptBlock
Invoking ScriptBlock:
This is a script block

Ответ 4

Если вы действительно хотите передать имя функции в виде строки: используйте &, оператор вызова, чтобы вызвать ее:

function A {
  Param($functionToCall)
  # Note the need to enclose a command embedded in a string in $(...)
  Write-Host "I'm calling: $(& $functionToCall)"
}

Function C {
  "Function C"  # Note: Do NOT use Write-Host to output *data*.
}

A -functionToCall C

Что касается необходимости использовать $(...) внутри "...": см. Этот ответ, который объясняет правила раскрытия строк (интерполяции строк) PowerShell.

Выше I'm calling: Function C

Обратите внимание, как функция C использует неявный вывод (так же, как явно использует Write-Output) для возврата значения.
Write-Host как правило, является неподходящим инструментом для использования, если только намерение явно не записывать только на дисплей, минуя потоки вывода PowerShell.

Обычно вам нужен оператор & в следующих случаях:

  • Чтобы вызвать команду по имени или пути, через ссылку на переменную и/или если имя single- или двойные кавычки.

  • Чтобы вызвать блок скрипта.

Блоки сценариев являются предпочтительным способом передачи фрагментов кода в PowerShell; вышеприведенное можно переписать как (обратите внимание, что механизм вызова не меняется, только передаваемый аргумент):

function A {
  Param($scriptBlockToCall)
  Write-Host "I'm calling: $(& $scriptBlockToCall)"
}

Function C {
  "Function C"  # Note: Do NOT use Write-Host to output *data*.
}

A -scriptBlockToCall { C }

В любом случае для передачи аргументов просто поместите их после: & <commandNameOrScriptBlock>; обратите внимание, как splatting (@<var>) используется для передачи несвязанных аргументов, хранящихся в автоматической переменной $Args.

function A {
  Param($commandNameOrScriptBlockToCall)
  Write-Host "I'm calling: $(& $commandNameOrScriptBlockToCall @Args)"
}

Function C {
  "Function C with args: $Args"
}


A -commandNameOrScriptBlockToCall C one two # by name
A -commandNameOrScriptBlockToCall { C @Args } one two # by script block

Выше I'm calling: Function C with args: one two дважды.

Ответ 5

Решение Duncan отлично поработало для меня. Однако я столкнулся с некоторыми проблемами, когда в имени функции была тире.

Мне удалось обойти это, построив третий пример:

function A{
    Param([scriptblock]$functionToCall)
    Write-Host "I'm calling $($functionToCall.Invoke(4))"
}

function Execute-FunctionWithDash($x)
{
    Write-Output "Function Execute-FunctionWithDash with $x"
}

PS C:\WINDOWS\system32> A -functionToCall { Param($x) Execute-FunctionWithDash $x }
I'm calling Function Execute-FunctionWithDash with 4

Ответ 6

для передачи по переменному числу именованных параметров

function L($Lambda){
   write-host "'nI'm calling $Lambda"
   write-host "'nWith parameters"; ft -InputObject $Args
   & $Lambda @Args
}

кажется, хорошо работает со странными именами функций

function +Strange-Name($NotUsed,$Named1,$Named2){
   ls -filter $Named1 -Attributes $Named2
}

PS C:\>L +Strange-Name -Named1 *.txt -Named2 Archive

и exe файлы, а также

PS C:\>L grep.exe ".*some text.*" *.txt

хотя, похоже, вам все еще нужно остерегаться инъекций

function inject($OrigFunction){
   write-host 'pre-run injection'
   & $OrigFunction @Args
   write-host 'post-run injection'
}

PS C:\>L inject +Strange-Name -Named1 *.txt -Named2 Archive

Ответ 7

    function strdel($a,$b,$c) {
    return ($a.substring(0,$b)+$(substr $a $c $a.length))
}
function substr($a,$b,$c) {
    return $a.substring($b,($c-$b))
}

$string = "Bark in the woods"
$in = $(substr $(strdel $string 0 5) 0 2)
write-host $in

Где Функция 'substr' вызвала функцию 'strdel' в качестве $ a paramater.

Функции с https://github.com/brandoncomputer/vds

Ответ 8

Как насчет:

function A{
Param($functionToCall)
    $res = Invoke-Command $functionToCall 
    Write-Host "I'm calling : $res"
}

function B{
    "Function B"
}

Function C{
    "Function C"
}

A -functionToCall ${function:C}