Рассмотрим следующую произвольную функцию и тестовые примеры:
Function Foo-MyBar {
Param(
[Parameter(Mandatory=$false)]
[ScriptBlock] $Filter
)
if (!$Filter) {
$Filter = { $true }
}
#$Filter = $Filter.GetNewClosure()
Get-ChildItem "$env:SYSTEMROOT" | Where-Object $Filter
}
##################################
$private:pattern = 'T*'
Get-Help Foo-MyBar -Detailed
Write-Host "`n`nUnfiltered..."
Foo-MyBar
Write-Host "`n`nTest 1:. Piped through Where-Object..."
Foo-MyBar | Where-Object { $_.Name -ilike $private:pattern }
Write-Host "`n`nTest 2:. Supplied a naiive -Filter parameter"
Foo-MyBar -Filter { $_.Name -ilike $private:pattern }
В тесте 1 мы пропускаем результаты Foo-MyBar
через фильтр Where-Object
, который сравнивает возвращенные объекты с шаблоном, содержащимся в частной переменной $private:pattern
. В этом случае это правильно возвращает все файлы/папки в C:\, которые начинаются с буквы T
.
В тесте 2 мы передаем тот же скрипт фильтрации непосредственно в качестве параметра в Foo-MyBar
. Однако к тому времени, когда Foo-MyBar
запускает фильтр, $private:pattern
не попадает в область действия, и поэтому он не возвращает никаких элементов.
Я понимаю, почему это так, потому что ScriptBlock, переданный в Foo-MyBar
, не является замыканием, поэтому не закрывается над переменной $private:pattern
, и эта переменная теряется.
Из комментариев я заметил, что ранее у меня был ошибочный третий тест, который пытался пройти {...}.GetNewClosure(), но это не закрывало переменные с частной областью действия. Спасибо @PetSerAl за помощь в разъяснении этого. .
Вопрос в том, как Where-Object
фиксирует значение $private:pattern
в тесте 1 и как добиться такого же поведения в наших собственных функциях/командлетах?
(Желательно, чтобы вызывающему абоненту не требовалось знать о замыканиях или знать, как передать сценарий фильтра в качестве замыкания.)
Замечу, что если я раскомментирую строку $Filter = $Filter.GetNewClosure()
внутри Foo-MyBar
, то она никогда не вернет никаких результатов, потому что $private:pattern
теряется.
(Как я уже сказал выше, функция и параметр здесь произвольны, как кратчайшее воспроизведение моей реальной проблемы!)
GetNewClosure
не фиксируетprivate
переменных. - person user4003407   schedule 16.08.2018$private:pattern
закрывается, но я не могу воссоздать его в новом окне. Однако вопрос остается в силе, учитывая, что Тест 1 все еще работает, как описано. - person jimbobmcgee   schedule 16.08.2018Remove-Variable pattern
сбросьте его - я должен был определить$pattern
в какой-то момент ранее. Я обновлю, чтобы удалить ссылку на тест 3 - person jimbobmcgee   schedule 16.08.2018Foo-MyBar
в отдельный модуль. - person user4003407   schedule 16.08.2018