如何正确使用List的ForEach()语句?

时间:2018-12-17 22:12:47

标签: powershell azure-powershell

我对List的ForEach方法语法中做错的事情感到困惑吗?

PS D:\ntt> $nicInfo.IpConfigurations.Count
2
PS D:\ntt> $nicInfo.IpConfigurations[0]

PrivateIpAddressVersion Name      Primary PrivateIpAddress PrivateIpAllocationMethod Subnet Name PublicIpAddress Name ProvisioningState
----------------------- ----      ------- ---------------- ------------------------- ----------- -------------------- -----------------
IPv4                    ipconfig1 True    10.233.0.4       Dynamic                                                    Succeeded


PS D:\ntt> $nicInfo.IpConfigurations.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     List`1                                   System.Object


PS D:\ntt> $nicInfo.IpConfigurations.ForEach({$_})
PS D:\ntt>

3 个答案:

答案 0 :(得分:2)

问题是在这种情况下, PowerShell's own .ForEach() collection methodthe List<T> type's own .ForEach() method 抢占了

  • PowerShell自己的.ForEach({ ... })

    • $_定义为脚本块参数({ ... })的输入对象
    • 将脚本块内部产生的所有输出传递(到PowerShell的成功输出流)。
  • 相反,List<T>的{​​{1}}将脚本块转换为.ForEach({ ... })委托,具有以下含义:

    • 委托人不了解脚本块内的Action<T>,而是收到一个必须以$_访问的单个参数

    • 脚本块中的
    • 输出被忽略 ,因为根据定义,$args[0]委托没有返回值。

      • 虽然您可以从脚本块中使用Action<T>生成 host (控制台)输出,但不能以编程方式使用此类输出,因为它绕过了PowerShell的输出流,因此无法捕获或重定向。

帽子PetSerAl的提示,用于在评论中提供关键的指针。

解决方法

  • 如果您传递给Write-Host的脚本块不需要产生任何输出,那么只需使用.ForEach()代替$args[0]在您的脚本块中,尽管您仍然可以选择使用以下其他解决方法之一,以避免造成混淆。

  • 如果需要输出 ,最简单的解决方案是使用$_List<T>实例转换为 array 首先.ToArray()将按预期工作;一个简化的例子:

    .ForEach()

    上面的代码按预期产生$list = [System.Collections.Generic.List[object]] ('foo', 'bar') $list.ToArray().ForEach({ $_ + '!' }) # Note the .ToArray() call.

    • 或者,您可以使用:

      • 一个'foo!', 'bar!'循环来处理列表项,这意味着您必须选择一个迭代变量名称并在循环体中引用该变量而不是foreach;例如:
        $_
      • foreach ($itm in $list) { $itm + '!' }管道中(速度较慢,但​​不需要更改脚本块),如No Refunds No Returns' answer所示;例如:
        ForEach-Object

答案 1 :(得分:1)

您是否要对集合中的每个项目进行处理?您想做这样的事情吗?

$nicInfo.IpConfigurations | ForEach-Object {
  $ipConfiguration = $_
  write-Output $ipConfiguration
  # do more stuff with this $ipConfiguration
}

答案 2 :(得分:1)

仅供参考,您可以将此代码用于list.ForEach()。

$nicInfo.IpConfigurations.ForEach({write-host $args[0].ToString()})

我自己测试一下,它可以工作。示例代码如下:

$s=New-Object System.Collections.Generic.List[string]
$s.Add("hello_1")
$s.Add("hello_2")
$s.Add("hello_3")
$s.ForEach({write-host $args[0].ToString()})

测试结果如下:

enter image description here

和我发现类似的issue一样,@ PetSerAl在这里的解释也很好。