PowerShell ForEach / путаница трубопроводов - PullRequest
11 голосов
/ 24 октября 2010

Я использую командлеты TFS PowerTools в PowerShell, чтобы попытаться получить некоторую информацию о наборах изменений и связанных рабочих элементах с моего сервера.Я свел проблему к поведению, которое я не понимаю, и я надеюсь, что оно не специфично для TFS (так что кто-то может объяснить мне проблему :))

Вот единственная команда, котораяЯ могу приступить к работе:

Get-TfsItemHistory C:\myDir -recurse -stopafter 5 | % { Write-Host $_.WorkItems[0]["Title"] }

Он делает то, что я ожидаю - Get-TfsItemHistory возвращает список из 5 ChangeSets и направляет их в foreach, который печатает заголовок первого связанного WorkItem.Так в чем моя проблема?Я пытаюсь написать большой скрипт и предпочитаю кодировать вещи, чтобы они больше походили на программу на C # (синтаксис powershell заставляет меня плакать).Всякий раз, когда я пытаюсь выполнить вышеописанное любым другим способом, коллекция WorkItems равна нулю.

Следующие команды (которые я интерпретирую как логически эквивалентные) не работают (коллекция WorkItems равна нулю):

$items = Get-TfsItemHistory C:\myDir -recurse -stopafter 5
$items | ForEach-Object { Write-Host $_.WorkItems[0]["Title"] }

Тот, который я бы действительно предпочел:

$items = Get-TfsItemHistory C:\myDir -recurse -stopafter 5
foreach ($item in $items)
{
    $item.WorkItems[0]["Title"]
    # do lots of other stuff
}

Я прочитал статью о разнице между оператором 'foreach' и командлетом ForEach-Object, но, похоже, это скореедебаты производительности.Это действительно кажется проблемой, когда используется трубопровод.

Я не уверен, почему все три из этих подходов не работают.Любое понимание приветствуется.

1 Ответ

12 голосов
/ 24 октября 2010

Это действительно сбивает с толку. На данный момент обходной путь заключается в том, чтобы захватить элементы, например, так:

$items = @(Get-TfsItemHistory . -r -Stopafter 25 | 
           Foreach {$_.WorkItems.Count > $null; $_})

Получает доступ к коллекции WorkItems, которая, по-видимому, вызывает заполнение этого свойства (я знаю - WTF?). Я склонен использовать @() для генерации массива в тех случаях, когда я хочу использовать ключевое слово foreach. С ключевым словом foreach дело в том, что оно будет повторять скалярное значение, включая $ null. Таким образом, если запрос ничего не возвращает, $items получает присвоенный $ null, и foreach будет повторять цикл один раз с $item, установленным в null. Теперь PowerShell обычно очень хорошо работает с нулями. Однако, если вы возвращаете это значение в .NET Framework, оно обычно не так простительно. @() будет гарантировать массив с 0, 1 или N элементами в нем. Если оно равно 0, цикл foreach вообще не будет выполнять свое тело.

Кстати, ваш последний подход - foreach ($item in $items) { ... } - должен работать просто отлично.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...