如何正确使用List的ForEach()语句? [英] How do I properly use ForEach() statement of List?

查看:2207
本文介绍了如何正确使用List的ForEach()语句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对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>

解决方案

问题 PetSerAl 的提示,以提供评论中的关键指针. >

解决方法:

  • 如果您传递给.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 + '!' }
      • 管道中的
      • ForEach-Object(速度较慢,但​​不需要更改脚本块),如;例如:
        $list | ForEach-Object { $_ + '!' }

I'm confused what I'm doing wrong in ForEach method syntax of List?

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>

The problem is that PowerShell's own .ForEach() collection method is preempted by the List<T> type's own .ForEach() method in this case:

  • PowerShell's own .ForEach({ ... }):

    • defines $_ as the input object at hand for the script-block argument ({ ... })
    • passes any output produced inside the script block through (to PowerShell's success output stream).
  • By contrast, List<T>'s .ForEach({ ... }) converts the script block to an Action<T> delegate, which has the following implications:

    • The delegate doesn't know about $_ inside the script block and instead receives a single argument that must be accessed as $args[0].

    • Output from the script block is ignored, because an Action<T> delegate by definition has no return value.

      • While you can produce host (console) output with Write-Host from within the script block, such output cannot be used programmatically, because it bypasses PowerShell's output streams and can therefore neither be captured nor redirected.

Tip of the hat to PetSerAl for providing the crucial pointers in comments.

Workarounds:

  • If the script block you pass to .ForEach() need not produce any output, all that's needed is to use $args[0] in lieu of $_ in your script block, though you may still opt to use one of the other workarounds below in order to avoid confusion.

  • If output is needed, the simplest solution is to convert the List<T> instance to an array with .ToArray() first, on which .ForEach() works as expected; a simplified example:

    $list = [System.Collections.Generic.List[object]] ('foo', 'bar')
    $list.ToArray().ForEach({ $_ + '!' }) # Note the .ToArray() call.
    

    The above produces 'foo!', 'bar!', as expected.

    • Alternatively, you may use:

      • a foreach loop to process the list items, which means you must pick an iteration variable name and refer to that instead of $_ in the loop body; e.g.:
        foreach ($itm in $list) { $itm + '!' }
      • or ForEach-Object in a pipeline (slower, but doesn't require changing the script block), as shown in No Refunds No Returns' answer; e.g.:
        $list | ForEach-Object { $_ + '!' }

这篇关于如何正确使用List的ForEach()语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆