循环中的Powershell值会丢失其值

Eri*_*ric 3 powershell

原谅标题,我不确定如何解释我所看到的.

示例代码:

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

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

$Results
Run Code Online (Sandbox Code Playgroud)

这很简单:

  • 创建一个包含5个数字的数组,以便在循环中使用
  • 使用名为ID的NoteProperty创建临时变量
  • 创建一个空数组来存储结果
  • 迭代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
    }
Run Code Online (Sandbox Code Playgroud)

这有效(你得到1,2,3,4,5作为你的结果).它看起来像$ Results只是持有多个对单个$ Result对象的引用,但是为什么将它移动到循环中可以解决问题呢?在这个例子中,$ Result是一个字符串,所以也许每次迭代都会创建一个新对象,但即使我强制$ Result为一个整数(由于整数不像字符串那样不可变,因此不应该重新创建一个新对象)仍然解决了问题,我得到了我期望的结果.

如果有人对这个解决问题的确切原因有任何了解,我会非常好奇.我有很多替代方案可以实现,但没有明确理解为什么这种方式有效,这让我烦恼.

Joe*_*ant 8

它通过进入循环来解决问题,因为那时你每次都创建一个新的$ Result对象,而不是在同一个上更改一个值(在数组中引用了5次).

它与您是否使用"" | Select ID或者123 | Select ID因为它只是PSCustomObject上的某种属性没有任何关系,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);
}
Run Code Online (Sandbox Code Playgroud)

希望你可以看到移动var Result = new CustomObject(){ ID = "" }的内部foreach循环将使其更好地工作,并且同样的概念在PowerShell中也是如此.

  • 这是一些更多的解释.PowerShell可以使用其扩展类型系统向对象添加属性和成员.但是你无法像这样修改普通的.NET对象.所以PowerShell用PSObject包装它们,它具有魔力.有时您直接拥有此对象(如Select-Object之后).有时它对你来说是透明的,就像这两个例子一样.`ps | select -first 1 | gm`与`(ps | select -first 1).PSBase | gm` (3认同)