2013-05-25 4 views
4

Il semble que les fermetures PowerShell ne saisissent pas la définition des fonctions:Fonction de capture dans PowerShell Fermeture

PS C:\> function x() { Write-Host 'original x' } 
PS C:\> function x-caller-generator() { return { Write-host 'Calling x!'; x }.GetNewClosure() } 
PS C:\> $y = x-caller-generator 
PS C:\> & $y 
Calling x! 
original x 
PS C:\> function x() { Write-Host 'new x' } 
PS C:\> & $y 
Calling x! 
new x 

Est-il possible de saisir la définition d'une fonction?

Ce que je ressens réellement, c'est que je crée une fermeture, mais quand ma fermeture est exécutée, la fonction est hors de portée en quelque sorte. (Il est un peu étrange module psake pour les scripts de build est en train de faire.) Quelque chose comme ceci:

PS C:\> function closure-maker() { 
>>  function x() { Write-Host 'x!' } 
>> 
>>  return { Write-host 'Calling x'; x }.GetNewClosure() 
>> } 
>> 
PS C:\> $y = closure-maker 
PS C:\> & $y 
Calling x 
The term 'x' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. 
At line:3 char:39 
+  return { Write-host 'Calling x'; x <<<< }.GetNewClosure() 
    + CategoryInfo   : ObjectNotFound: (x:String) [], CommandNotFoundException 
    + FullyQualifiedErrorId : CommandNotFoundException 

Remarque: L'utilisation PowerShell 2.0, mais intéressé par 3.0 réponses s'il y a quelque chose de nouveau.

Répondre

2

Eh bien, j'ai trouvé quelque chose qui fonctionne au moins pour des fonctions simples. Nous pouvons utiliser Get-Item pour obtenir un objet décrivant la fonction, puis extraire le script original. Comme ceci:

function x-caller-generator() { 
    $xFunc = [ScriptBlock]::Create((Get-Item function:x).Definition) 
    return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() 
} 

Si la fonction est jamais redéfinie (comme dans mon exemple où ma fonction est hors de portée), nous pouvons éviter de tirer au large de la définition et il suffit d'utiliser l'objet fonction directement:

function closure-maker() { 
    function x() { Write-Host 'x!' } 

    $xFunc = Get-Item function:x 
    return { Write-host 'Calling x'; & $xFunc }.GetNewClosure() 
} 

Cette seconde méthode fonctionnera et non si la fonction est redéfinie (au moins dans la même portée que la fonction d'origine) avant l'exécution de la fermeture. L'objet est apparemment dynamique; il suit la définition actuelle. Je doute sérieusement que cela fonctionnerait avec une fonction qui fait référence à d'autres fonctions définies par l'utilisateur qui pourraient également être hors de portée, mais mon cas d'utilisation ne l'exigeait pas.

Exemple de sortie:

Création bloc de script

PS C:\> function x() { Write-Host 'original x' } 
PS C:\> function x-caller-generator() { $xFunc = [ScriptBlock]::Create((Get-Item function:x).Definition); return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() } 
PS C:\> $y = x-caller-generator 
PS C:\> & $y 
Calling x! 
original x 
PS C:\> function x() { Write-Host 'new x' } 
PS C:\> & $y 
Calling x! 
original x 

utilisant l'objet fonction

PS C:\> function closure-maker() { 
>>  function x() { Write-Host 'x!' } 
>> 
>>  $xFunc = Get-Item function:x 
>>  return { Write-host 'Calling x'; & $xFunc }.GetNewClosure() 
>> } 
>> 
PS C:\> $y = closure-maker 
PS C:\> & $y 
Calling x 
x! 

Essayer d'utiliser l'objet avec le premier exemple ne fonctionne pas:

PS C:\> function x() { Write-Host 'original x' } 
PS C:\> function x-caller-generator() { $xFunc = Get-Item function:x; return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() } 
PS C:\> $y = x-caller-generator 
PS C:\> & $y 
Calling x! 
original x 
PS C:\> function x() { Write-Host 'new x' } 
PS C:\> & $y 
Calling x! 
new x 
0

Une petite correction que le premier exemple, le travail:

clear 
function x() { Write-Host 'original x' } 
function x-caller-generator() { 
     $xFunc = $function:x; # instead of Get-Item 
     return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() 
} 
$y = x-caller-generator 
& $y 
function x() { Write-Host 'new x' } 
& $y 

Sortie:

Calling x! 
original x 
Calling x! 
original x 

PowerShell a un trop grand nombre se ressemble qui se comportent en fait différemment. Vous pouvez obtenir un objet fonction en utilisant le préfixe $ function. On pourrait penser qu'il fonctionne de la même manière que le Get-Item, mais il ne le fait pas ...

Questions connexes