PowerShell Add-Member ...奇怪的行为?

PowerShell Add-Member ... odd behaviour?

谁能解释一下使用 Add-MemberPSCustomObject 对象添加属性时出现的奇怪行为?出于某种原因,一旦您添加了成员​​,该对象在显示时将像 hashtable 一样表示,即使它仍然是 PSCustomObject,例如:

创建一个简单的对象:

[PSCustomObject] $test = New-Object -TypeName PSCustomObject -Property @{ a = 1; b = 2; c = 3; }

检查其类型:

$test.GetType();

...其中 returns:

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

然后获取其内容:

$test;

...其中 returns:

c b a
- - -
3 2 1

添加一个属性:

Add-Member -InputObject $test -MemberType NoteProperty -Name d -Value 4 -TypeName Int32;

确认其类型没有改变:

$test.GetType();

...其中 returns:

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

最后,再次获取其内容:

$test;

...其中 returns:

@{c=3; b=2; a=1; d=4}

而我希望得到:

c d b a
- - - -
3 4 2 1

任何想法都将受到欢迎,因为多年来我一直在挑剔这个问题。

非常感谢

Add-Member 调用中省略 -TypeName Int32 参数 指定 -Value 参数的类型.

# Do NOT use -TypeName, unless you want to assign the custom
# object stored in $test a specific ETS type identity.
Add-Member -InputObject $test -MemberType NoteProperty -Name d -Value 4

请注意,Int32 ([int]) 隐含 可以解释为适合 [=17] 的不带引号的参数=]范围,如4.

如果确实需要明确指定类型,请在 expression 中使用 cast,例如... -Value ([long] 4)


至于你试过的

-TypeName Int32 指定此类型的全名,System.Int32,作为 ETS 类型名称列表中的第一个条目 输入对象 关联。 (ETS 是 PowerShell 的 Extended Type System。)

您可以通过访问 intrinsic .pstypenames property (and you also see its first entry in the header of Get-Member 的输出来查看此列表):

PS> $test.pstypenames

System.Int32
System.Management.Automation.PSCustomObject
System.Object

如您所见,System.Int32 插入在对象的真实 .NET 类型标识 (System.Management.Automation.PSCustomObject) 之前;其余条目显示继承层次结构。

此类 ETS 类型名称通常用于将自定义行为与对象相关联,而不考虑它们真正的 .NET 类型标识,特别是关于 扩展类型(参见about_Types.ps1xml) or associating custom display formatting with it (see about_Format.ps1xml)。

由于 PowerShell 随后认为您的 [pscustomobject] 属于 [int] (System.Int32) 类型,因此它对其应用了该类型的常用输出格式,这实际上意味着调用 .ToString() 在实例上。

[pscustomobject] 实例上调用 .ToString() 会生成您看到的哈希表- 类似 的表示,如以下示例所示:

  • 注意使用 PSv3+ 语法糖 来创建 [pscustomobject] 实例 ([pscustomobject] @{ ... }),这不仅比 New-Object 调用,但也 保留 属性 顺序
PS> ([pscustomobject] @{ a = 'foo bar'; b = 2}).psobject.ToString()

@{a=foo bar; b=2}

请注意内部 .psobject 属性 的使用,这是解决 direct 的长期错误所必需的.ToString() 调用 [pscustomobject] 个实例 return 空字符串 - 参见 GitHub issue #6163.