Значения Powershell внутри цикла теряют свое значение - PullRequest
3 голосов
/ 03 июня 2011

Простите за заголовок, я не совсем уверен, как объяснить, что я вижу.

Пример кода:

    $SampleValues = 1..5
    $Result = "" | Select ID
    $Results = @()  

    $SampleValues | %{
        $Result.ID = $_
        $Results += $Result
    }

$Results

Это довольно просто:

  • Создание массива с 5 числами для использования в цикле
  • Создание временной переменной с NoteProperty с именем ID
  • Создание пустого массива для хранения результатов
  • Выполните итерацию по каждому из 5 чисел, присваивая их временной переменной, затем добавляя ее к массиву.

Ожидаемый результат - 1,2,3,4,5, но при запуске возвращается 5,5, 5,5,5

Это простой пример, взятый из гораздо более сложного сценария, и я пытаюсь выяснить, почему результат такой, какой он есть.На каждой итерации все элементы, которые уже были добавлены в $ Results, обновляют свои значения до самого последнего значения.Я протестировал принудительное преобразование всего в $ Script: или $ Global: scope и получил те же результаты.

Единственное решение, которое я нашел, это следующее, которое перемещает объявление $ Result в цикл.

    $SampleValues = 1..5
    $Results = @()

$SampleValues | %{
    $Result = "" | Select ID
    $Result.ID = $_
    $Results += $Result
    }

Это работает (вы получаете 1,2,3,4,5 в качестве ваших результатов).Похоже, что $ Results просто содержит несколько ссылок на отдельный объект $ Result, но почему перемещение этого в цикл решает проблему?В этом примере $ Result является строкой, поэтому, возможно, он создает новый объект каждую итерацию, но даже когда я заставил $ Result быть целым числом (которое не должно воссоздавать новый объект, так как целое число не является неизменным, как строка), этоЯ все еще решил проблему, и я получил ожидаемый результат.

Если кто-нибудь знает, почему именно это решает проблему, мне будет очень любопытно.Есть много альтернатив для меня, но я не понимаю, почему это так, и это меня беспокоит.

Ответы [ 2 ]

8 голосов
/ 03 июня 2011

Это устраняет проблему, переходя в цикл, потому что тогда вы каждый раз создаете новый объект $ Result, а не изменяете значение на одно и то же (ссылка 5 раз в массиве).

Это не имеет никакого отношения к тому, используете ли вы "" | Select ID или 123 | Select ID, потому что это просто становится своего рода свойством в PSCustomObject, который по-прежнему является ссылочным типом, а не типом значения.

Помните, что Powershell - это все .NET внутри. Вот некоторый C #, аналогичный тому, что делает Powershell в вашем первом примере, который привел ко всем 5 (надеюсь, вы знаете C #):

var SampleValues = new []{1,2,3,4,5};
var Result = new CustomObject(){ ID = "" };
var Results = new List<Object>();

foreach (var _ in SampleValues) {
    Result.ID = _;
    Results.Add(Result);
}

Надеюсь, вы увидите, как перемещение var Result = new CustomObject(){ ID = "" } внутри цикла foreach улучшит его работу, и та же концепция верна в Powershell.

1 голос
/ 03 июня 2011

В этом примере $ Result является строкой, поэтому, возможно, он создает новый объект каждую итерацию, но даже когда я вынудил $ Result быть целым числом (которое не должно воссоздавать новый объект, поскольку целое число неизменяемый как строка) это все еще решило проблему, и я получил ожидаемый результат.

На самом деле, в вашем примере $ Result не является строкой. Это универсальный объект с одним свойством (ID), которое является строкой.

Переменные Powershell бывают двух типов - значения и ссылки. Строка или целое число передается по значению, объект передается по ссылке. Добавляя $ result к $ results 5 раз, вы получаете 5 ссылок на один объект $ result, а не 5 различных объектов.

Если мы добавим свойство $ result.id (целочисленный тип / тип значения) к $ results вместо объекта $ result, мы получим:

 $SampleValues = 1..5
     $Result = "" | Select ID
     $Results = @()  

     $SampleValues | %{
         $Result.ID = $_
         $Results += $Result.ID
     }

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