为什么在Powershell的内置类型上添加成员会发生这种奇怪的行为?

为什么在Powershell的内置类型上添加成员会发生这种奇怪的行为?,powershell,Powershell,鉴于此: $x = new-object psobject $x | add-member noteproperty test 'xtest' $x.test $x | add-member noteproperty test2 'xtest2' $x.test2 $y = @{} $y | add-member noteproperty test 'ytest' $y.test $y | add-member noteproperty test2 'ytest2' $y.test2 输出是

鉴于此:

$x = new-object psobject
$x | add-member noteproperty test 'xtest'
$x.test
$x | add-member noteproperty test2 'xtest2'
$x.test2
$y = @{}
$y | add-member noteproperty test 'ytest'
$y.test
$y | add-member noteproperty test2 'ytest2'
$y.test2
输出是我所期望的:

xtest
xtest2
但鉴于此:

$x = new-object psobject
$x | add-member noteproperty test 'xtest'
$x.test
$x | add-member noteproperty test2 'xtest2'
$x.test2
$y = @{}
$y | add-member noteproperty test 'ytest'
$y.test
$y | add-member noteproperty test2 'ytest2'
$y.test2
我只得到:

ytest2
我很困惑。如果我这样做:

$y = @{}
$y | add-member noteproperty test 'ytest'
$y | add-member noteproperty test2 'ytest2'
$y.test
$y.test2
那么就根本没有输出了。运行get members可以确认没有实际添加这些方法


这是怎么回事?这一定是我的愚蠢,但我看不出来。

这是因为power shell打开了你的空列表。如果要向列表中添加属性,请使用inputobject参数

add-member -input $y noteproperty test1 'ytest1'
您在问题中描述的用法会将一个成员添加到列表中您在本例中看到的每个项目中

C:(...)SequenceId>$y = @()
C:(...)SequenceId>$y += New-Object -t psobject
C:(...)SequenceId>$y += New-Object -t psobject
C:(...)SequenceId>$Y | Add-Member -type noteproperty -name hi -value you
C:(...)SequenceId>$Y

hi
--
you
you
@Joey提出了这个问题,我使用了一个数组,这个数组是直接可写的。要让OP语义按照我说的做,您必须执行以下操作

C:(...)SequenceId>$y = @{}
C:(...)SequenceId>$y["one"] = New-Object -t psobject
C:(...)SequenceId>$y["two"] = New-Object -t psobject
C:(...)SequenceId>$Y | Add-Member -type noteproperty -name hi -value you
C:(...)SequenceId>$y

Name                           Value
----                           -----
two
one

C:(...)SequenceId>$Y.values | Add-Member -type noteproperty -name hi -value you
C:(...)SequenceId>$y

Name                           Value
----                           -----
two                            @{hi=you}
one                            @{hi=you}

IIRC这实际上与PSObject包装器有关,它是PowerShell 2.0中扩展类型系统的关键部分。执行此操作时:

$x = new-object psobject
$x | add-member noteproperty test 'xtest'
$x.test
因为对象已经是PSObject,所以Add成员可以将新的NoteProperty直接添加到PSObject,例如:

$y = @{}
$y | add-member noteproperty test 'ytest'
$y.test
这不起作用,因为
$y
最初没有包装,所以当执行addmember时,它会创建一个新对象来包装原始哈希表。您可以通过使用Get Member查看这一点,例如:

$y | Get-Member
您将看不到您的
test
属性。要使其在v2中工作,必须执行以下操作:

$y = $y | add-member noteproperty test ytest -passthru
$y.test
ytest
仅供参考,这在V3中有所更改,因为它基于DLR,它直接修改对象,而不创建新的包装器对象,例如:

# PowerShell V3 only
16# $y = @{}
17# Add-Member -InputObject $y test ytest
18# $y.test
ytest

请注意细微的语法差异。他们使用的是哈希表,而不是数组。哈希表根本不会被迭代(您必须使用
GetEnumerator()
来执行此操作。例如,
@{}}124;%{$| gm}
将告诉您,哈希表本身是通过管道找到的,而不是任何元素。Neato。感谢您提供的详细答案以及有关Posh 3的信息!实际上..备份了一点..为什么我从两个ytest示例中看到了不同的结果?不完全确定,但我知道如果您强制创建psobject包装器,从这一点开始,它在例如
$y=@{};$y.psobject
上的行为正常,然后执行示例的其余部分,它就可以正常工作。也许原始示例中的第一个Add成员创建了psobject包装器作为副作用,然后它就可以工作了。无论如何,闻起来像个bug。
$y.test
创建了psobject包装器。