Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The .ForEach() array method misbehaves with XmlElement instances if the name of the property to extract is passed as a string #15994

Closed
5 tasks done
mklement0 opened this issue Aug 25, 2021 · 8 comments
Labels
Issue-Bug Issue has been identified as a bug in the product Resolution-No Activity Issue has had no activity for 6 months or more WG-Engine core PowerShell engine, interpreter, and runtime

Comments

@mklement0
Copy link
Contributor

mklement0 commented Aug 25, 2021

Prerequisites

Steps to reproduce

The forms $collection.ForEach('someProp') and $collection.ForEach({ $_.someProp }) should be equivalent and generally are (the former being faster).

However, with an (adapted) XmlElement enumerating the child elements with .ForEach('someProp') does not work as expected: it returns the child elements as an array in the first element of the returned collection.

[xml] $xml = '<foo><child>A</child><child>B</child></foo>'
$hash = @{ foo = [pscustomobject] @{ child = 'A'}, [pscustomobject] @{ child = 'B' } } # control
$r = $hash.foo.ForEach('child'); [pscustomobject] @{ Count = $r.Count; TypeOfFirstElem = $r[0].GetType().Name; ValueOfFirstElem = $r[0] }
$r = $xml.foo.ForEach('child'); [pscustomobject] @{ Count = $r.Count; TypeOfFirstElem = $r[0].GetType().Name; ValueOfFirstElem = $r[0] }
$r = $xml.foo.ForEach({ $_.child }); [pscustomobject] @{ Count = $r.Count; TypeOfFirstElem = $r[0].GetType().Name; ValueOfFirstElem = $r[0] }

Expected behavior

Count TypeOfFirstElem ValueOfFirstElem
----- --------------- ----------------
    2 String          A
    2 String          A
    2 String          A

Actual behavior

Count TypeOfFirstElem ValueOfFirstElem
----- --------------- ----------------
    2 String          A
    1 Object[]        {A, B}
    2 String          A

Error details

No response

Environment data

PowerShell Core 7.2.0-preview.9

Visuals

No response

@mklement0 mklement0 added the Needs-Triage The issue is new and needs to be triaged by a work group. label Aug 25, 2021
@mklement0 mklement0 changed the title The .ForEach() array method misbehaves with XmlElement instances if a property name to extract is passed as a string The .ForEach() array method misbehaves with XmlElement instances if the name of the property to extract is passed as a string Aug 26, 2021
@iSazonov iSazonov added WG-Engine core PowerShell engine, interpreter, and runtime Issue-Bug Issue has been identified as a bug in the product labels Aug 26, 2021
@rkeithhill
Copy link
Collaborator

rkeithhill commented Oct 28, 2021

Just a guess but it looks like the ForEach('child') invocation is outputting a collection without the enumerate option.

PS> [xml] $xml = '<foo><child>A</child><child>B</child></foo>'
PS> $xml.foo.ForEach('child').GetType()

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

PS> $xml.foo.ForEach('child')
A
B

PS> $xml.foo.ForEach('child') | % {$_}
A
B

PS> $xml.foo.ForEach('child') | % {$_} | % GetType

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object
True     True     String                                   System.Object

@mklement0
Copy link
Contributor Author

@rkeithhill, note that .ForEach() always returns a System.Collections.ObjectModel.Collection<T> instance, even for a single output object (e.g. ('foo').foreach('length').GetType())

The problem here, as demonstrated in the OP, is that the single output object is itself an array (object[]), unexpectedly, whereas $xml.foo.child enumerates as usual.

@rkeithhill
Copy link
Collaborator

> $xml.foo.ForEach('child')[0].GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Ah, yup.

@daxian-dbw
Copy link
Member

I dug a little under the debugger and here are what I found:

  1. When running $xml.foo.ForEach(...), $xml.foo is treated as a single element XmlElement foo. So the operation done within ForEach will be targeting $xml.foo. However, $hash.foo is an array of 2 elements, so it's not really comparable to $xml.foo and thus we can ignore it in this context.

  2. $xml.foo.child always return an array of 2 elements. The difference between .ForEach('child') and .ForEach({$_.child}) is:

This is why single output object is itself an array.
Not super sure how to fix it though. One option is to always unwrap collection when accessing a property or calling a method via the .ForEach(<member-name>) syntax.

@daxian-dbw daxian-dbw removed their assignment Oct 29, 2021
@daxian-dbw daxian-dbw removed the Needs-Triage The issue is new and needs to be triaged by a work group. label Oct 29, 2021
Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

2 similar comments
Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

@microsoft-github-policy-service microsoft-github-policy-service bot added Resolution-No Activity Issue has had no activity for 6 months or more labels Nov 16, 2023
Copy link
Contributor

This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Bug Issue has been identified as a bug in the product Resolution-No Activity Issue has had no activity for 6 months or more WG-Engine core PowerShell engine, interpreter, and runtime
Projects
None yet
Development

No branches or pull requests

4 participants