I have found at least one difference how this method works with different types.
$array = 1,2,3,4,5,6
$arraylist = [System.Collections.ArrayList]::new(@(1,2,3,4,5,6))
$list = [System.Collections.Generic.List[object]]::new(@(1,2,3,4,5,6))
$array.foreach{$_}
1
2
3
4
5
6
$arraylist.foreach{$_}
1
2
3
4
5
6
$list.foreach{$_}
# nothing
# workaround
@($list).foreach{$_}
1
2
3
4
5
6
Is it a type limitation, feature, or bug?
Foreach-Object cmdlet works as expected.
No secrets here. Some confusion, though. 馃檪
The .Foreach()"magic" method is only provided on objects that don't implement their own .Foreach() method; System.Collections.Generic.List<T> implements its own Foreach() method, so the magic method isn't available. You can check the overload definitions with $list.Foreach:
OverloadDefinitions
-------------------
void ForEach(System.Action[System.Object] action)
Without getting too deep into it, you _can_ use these in PS, but you need to be mindful of how they behave. Action<T> has _no return type_ (it's a void method with one input, effectively), so no matter what you do you can't get it to provide output / return values, the type is defined to provide no return value. Typically Func is used for actions with return values, if I recall correctly, but Action indicates no return value.
Also, when handling C# Action or Func, I don't believe $_ is typically defined; you usually need to use $args to handle that, or provide a param() block in your scriptblock to handle the input parameters to the Action or Func. In other words, this "works" (but provides no output as mentioned before):
$list.Foreach{ Write-Host $args[0] }
Something you _can_ do is use the ConvertAll() method instead, which does permit output values, but you need to cast the argument to the correct type deliberately, since it's a generic method and PS can't resolve that one on its own currently. Again, check overloads with $list.ConvertAll to see what you're dealing with, and something like this will work:
# without param
$list.ConvertAll([Converter[object, int]]{ $args[0] + 10 })
# with param
$list.ConvertAll(
[Converter[object,int]]{
param($item)
$item + 10
}
)
# both result in:
11
12
13
14
15
16
@vexx32 thanks. I believe @($list).foreach{$_} is more simple solution.
.foreach and .where methods are really confusing. Both return different from original collection type
System.Collections.Generic.List1[[System.Management.Automation.PSObject, System.Management.Automation, Ve
rsion=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]
(backtick before "1" is lost)
New type corresponds by name to generic.list but with less amount of methods
Most helpful comment
No secrets here. Some confusion, though. 馃檪
The
.Foreach()"magic" method is only provided on objects that don't implement their own.Foreach()method;System.Collections.Generic.List<T>implements its ownForeach()method, so the magic method isn't available. You can check the overload definitions with$list.Foreach:Without getting too deep into it, you _can_ use these in PS, but you need to be mindful of how they behave.
Action<T>has _no return type_ (it's avoidmethod with one input, effectively), so no matter what you do you can't get it to provide output / return values, the type is defined to provide no return value. TypicallyFuncis used for actions with return values, if I recall correctly, butActionindicates no return value.Also, when handling C#
ActionorFunc, I don't believe$_is typically defined; you usually need to use$argsto handle that, or provide aparam()block in your scriptblock to handle the input parameters to the Action or Func. In other words, this "works" (but provides no output as mentioned before):Something you _can_ do is use the
ConvertAll()method instead, which does permit output values, but you need to cast the argument to the correct type deliberately, since it's a generic method and PS can't resolve that one on its own currently. Again, check overloads with$list.ConvertAllto see what you're dealing with, and something like this will work: