web-dev-qa-db-fra.com

Passer la fonction comme paramètre

J'ai écrit la fonction "A" qui appellera l'une des nombreuses autres fonctions. Pour enregistrer la fonction de réécriture 'A', je voudrais passer la fonction à appeler comme paramètre de la fonction 'A'. Par exemple:

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

Retours: j'appelle: C

Je m'attends à ce qu'il revienne: j'appelle: Fonction C.

J'ai essayé différentes choses telles que:

Param([scriptblock]$functionToCall)

Impossible de convertir System.String en ScriptBlock

A -functionToCall $function:C

Renvoie la fonction "Write-Host" C "

A - functionToCall (&C)

Cela évalue avant le reste:

 Function C
 I'm Calling :

Je suis sûr que c'est de la programmation 101, mais je ne peux pas trouver la bonne syntaxe ou ce que je fais mal.

32
woter324

Est-ce ce dont vous avez besoin?

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
6
Frode F.

Je ne suis pas sûr que ce soit le meilleur, mais:

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
39
Duncan

Avez-vous pensé à passer un ScriptBlock comme paramètre?

$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
8
Rustam

Si vous voulez vraiment passer le nom d'une fonction, comme chaîne: utilisez &, Le - opérateur d'appel, pour l'invoquer:

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

En ce qui concerne la nécessité d'utiliser $(...) à l'intérieur de "...": Voir cette réponse , qui explique les règles d'expansion de chaîne (interpolation de chaîne) de PowerShell.

Ce qui précède donne I'm calling: Function C

Notez comment la fonction C utilise la sortie implicite (identique à l'utilisation explicite de Write-Output) Pour renvoyer une valeur.
Write-Host Est généralement le mauvais outil à utiliser , sauf si l'intention est d'écrire explicitement sur l'écran uniquement, en contournant les flux de sortie de PowerShell.

Vous avez généralement besoin de l'opérateur & Dans les scénarios suivants:

  • Pour appeler une commande par nom ou chemin, via un référence de variable et/ou si le nom est entre guillemets simples ou doubles.

  • Pour appeler un bloc de script.

Les blocs de script ​​sont le moyen préféré de passer des morceaux de code dans PowerShell; ce qui précède pourrait être réécrit en (notez que le mécanisme d'invocation ne change pas, juste l'argument passé):

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 }

Dans les deux cas, pour passer arguments, placez-les simplement après: & <commandNameOrScriptBlock>; notez comment splatting (@<var>) est utilisé pour passer les arguments non liés stockés dans la variable automatique $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

Ce qui précède donne deux fois I'm calling: Function C with args: one two.

4
mklement0

La solution de Duncan a très bien fonctionné pour moi. Cependant, je rencontre certains problèmes lorsque le nom de la fonction contient un tiret.

J'ai pu contourner ce problème en construisant son troisième exemple:

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
3
Derek
    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

Où Function 'substr' appelait la fonction 'strdel' comme paramètre $ a.

Fonctions de https://github.com/brandoncomputer/vds

1
Brandon Cunningham

pour transmettre un nombre variable de paramètres nommés

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

semble bien fonctionner avec des noms de fonction étranges

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

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

et les fichiers exe ainsi

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

bien qu'il semble que vous ayez encore besoin de faire attention à l'injection

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
1
Gregor y

Que diriez-vous:

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}

Parcourez la fonction en tant que valeur à l'aide de $ {function: ...}. Appelez la fonction et enregistrez les résultats dans $ res.

0
Tomer