PowerShell Add-Member ...奇怪的行为?
PowerShell Add-Member ... odd behaviour?
谁能解释一下使用 Add-Member 向 PSCustomObject 对象添加属性时出现的奇怪行为?出于某种原因,一旦您添加了成员,该对象在显示时将像 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.
谁能解释一下使用 Add-Member 向 PSCustomObject 对象添加属性时出现的奇怪行为?出于某种原因,一旦您添加了成员,该对象在显示时将像 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.