Передать функцию в качестве параметра
Я написал функцию "А", которая будет вызывать одну из ряда других функций. Чтобы сохранить функцию перезаписи '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, но я не могу определить правильный синтаксис или что я делаю неправильно.
Ответы
Ответ 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}