PSObject,Hashtable和PSCustomObject之间的区别

mas*_*asi 30 powershell powershell-3.0 psobject

任何人都能解释一下细节吗?如果我使用创建对象

$var = [PSObject]@{a=1;b=2;c=3}
Run Code Online (Sandbox Code Playgroud)

然后我使用getType()PowerShell 查找它的类型告诉我它的类型为Hashtable.

当使用Get-Member(别名gm)来检查对象时,很明显已经创建了一个哈希表,因为它有一个keys和一个values属性.那么"普通"散列表的区别是什么?

另外,使用PSCustomObject有什么好处?使用这样的东西创建一个

$var = [PSCustomObject]@{a=1;b=2;c=3}
Run Code Online (Sandbox Code Playgroud)

对我来说唯一可见的区别是PSCustomObject的不同数据类型.此外,还有一个检查gm显示现在每个键都已添加为NoteProperty对象,而不是键和值属性.

但我有什么优势?我可以通过使用其键来访问我的值,就像在哈希表中一样.我可以在PSCustomObject中存储多个简单的键值对(例如键对象对),就像在哈希表中一样.那有什么好处?有什么重要的区别吗?

tko*_*sih 31

使用一种情况[PSCustomObject]而不是HashTable在需要它们的集合时.以下是说明它们处理方式的不同之处:

$Hash = 1..10 | %{ @{Name="Object $_" ; Index=$_ ; Squared = $_*$_} }
$Custom = 1..10 | %{[PSCustomObject] @{Name="Object $_" ; Index=$_ ; Squared = $_*$_} }

$Hash   | Format-Table -AutoSize
$Custom | Format-Table -AutoSize

$Hash   | Export-Csv .\Hash.csv -NoTypeInformation
$Custom | Export-Csv .\CustomObject.csv -NoTypeInformation
Run Code Online (Sandbox Code Playgroud)

Format-Table将产生以下结果$Hash:

Name    Value
----    -----
Name    Object 1
Squared 1
Index   1
Name    Object 2
Squared 4
Index   2
Name    Object 3
Squared 9
...
Run Code Online (Sandbox Code Playgroud)

以下是$CustomObject:

Name      Index Squared
----      ----- -------
Object 1      1       1
Object 2      2       4
Object 3      3       9
Object 4      4      16
Object 5      5      25
...
Run Code Online (Sandbox Code Playgroud)

同样的事情发生了Export-Csv,因此使用的原因[PSCustomObject]而不仅仅是普通的HashTable.


小智 17

说我想创建一个文件夹.如果我使用PSObject,你可以通过查看它来判断它是错误的

PS > [PSObject] @{Path='foo'; Type='directory'}

Name                           Value
----                           -----
Path                           foo
Type                           directory
Run Code Online (Sandbox Code Playgroud)

但是PSCustomObject看起来是正确的

PS > [PSCustomObject] @{Path='foo'; Type='directory'}

Path                                    Type
----                                    ----
foo                                     directory
Run Code Online (Sandbox Code Playgroud)

然后我可以管道对象

[PSCustomObject] @{Path='foo'; Type='directory'} | New-Item
Run Code Online (Sandbox Code Playgroud)

  • 投票,因为这正是我正在寻找的答案。 (2认同)

Loï*_*HEL 12

我认为PSObject的一个优点是你可以用它创建自定义方法.

例如,

$o = New-Object PSObject -Property @{
   "value"=9
}
Add-Member -MemberType ScriptMethod -Name "Sqrt" -Value {
    echo "the square root of $($this.value) is $([Math]::Round([Math]::Sqrt($this.value),2))"
} -inputObject $o

$o.Sqrt()
Run Code Online (Sandbox Code Playgroud)

您可以使用它来控制PSObject属性的排序顺序(请参阅PSObject排序)

  • 请注意,您可以使用 PSObject 或 PSCustomObject 来执行此操作。 (3认同)

Dav*_*e F 10

PSObject文档中

包装对象,以提供可用成员的替代视图以及扩展它们的方式。成员可以是方法,属性,参数化属性等。

换句话说,a PSObject是一个对象,您可以在创建对象后向其中添加方法和属性。

从“关于哈希表”文档中

哈希表(也称为字典或关联数组)是一种紧凑的数据结构,用于存储一个或多个键/值对。

...

哈希表经常被使用,因为它们对于查找和检索数据非常有效。

您可以使用a之PSObject类的,Hashtable因为PowerShell允许您向中添加属性PSObjects,但是您不应这样做,因为您将失去HashtableKeysand 功能等特定功能的访问权限Values。同样,可能会有性能成本和额外的内存使用情况。

PowerShell文档包含以下有关的信息PSCustomObject

当使用不带参数的PSObject的构造函数时,用作占位符BaseObject。

这是我不清楚,但在PowerShell的论坛一个帖子一些PowerShell的书的合着者似乎更加明显:

[PSCustomObject]是类型加速器。它构造了一个PSObject,但这样做的方式导致哈希表键成为属性。PSCustomObject本身不是对象类型,而是一个过程快捷方式。... PSCustomObject是一个占位符,当不使用构造函数参数调用PSObject时将使用该占位符。

关于您的代码,@{a=1;b=2;c=3}Hashtable[PSObject]@{a=1;b=2;c=3}不会将转换HashtablePSObject或产生错误。该对象仍然是Hashtable。但是,[PSCustomObject]@{a=1;b=2;c=3}Hashtable转换为PSObject。我找不到说明为什么会发生这种情况的文档。

如果要将a Hashtable转换为对象以将其键用作属性名称,则可以使用以下代码行之一:

[PSCustomObject]@{a=1;b=2;c=3}

# OR

New-Object PSObject -Property @{a=1;b=2;c=3}

# NOTE: Both have the type PSCustomObject
Run Code Online (Sandbox Code Playgroud)

如果要将大量的Hashtables键转换为键为属性名称的对象,可以使用以下代码:

@{name='a';num=1},@{name='b';num=2} |
 % { [PSCustomObject]$_ }

# OR

@{name='a';num=1},@{name='b';num=2} |
 % { New-Object PSObject -Property $_ }

<#
Outputs:

name num
---- ---
a      1
b      2
#>
Run Code Online (Sandbox Code Playgroud)

查找有关的文档NoteProperty非常困难。Add-Member文档中,除了-MemberType添加对象属性外没有其他有意义的东西NoteProperty。在Windows PowerShell中食谱(第3版)中定义的NotepropertyMembertype为:

由您提供的初始值定义的属性

  • Lee,H.(2013年)。Windows PowerShell食谱。O'Reilly Media,Inc. 895。

  • 好东西。请注意,“[PSCustomObject]@{a=1;b=2;c=3}”是“语法糖”,它“直接”构造自定义对象,而不是通过中间哈希表(尽管语法建议如此);如果涉及中间哈希表,则无法保证属性的顺序,但确实如此。请注意,类型加速器“[pscustomobject]”和“[psobject]”引用相同的类型“System.Management.Automation.PSObject”。但是,“纯”“PSObject”(仅具有 ETS 属性的自定义对象(不包装 .NET 对象)将其类型报告为“System.Management.Automation.PSCustomObject”。 (3认同)
  • 支持这一点是因为这似乎更详细地说明了每种参考资料与支持参考资料之间的区别。 (2认同)

Ada*_*oll 6

我认为你会看到的最大区别是性能。看看这篇博文:

有效组合对象——使用哈希表索引对象集合

作者运行了以下代码:

$numberofobjects = 1000

$objects = (0..$numberofobjects) |% {
    New-Object psobject -Property @{'Name'="object$_";'Path'="Path$_"}
}
$lookupobjects = (0..$numberofobjects) | % {
    New-Object psobject -Property @{'Path'="Path$_";'Share'="Share$_"}
}

$method1 = {
    foreach ($object in $objects) {
        $object | Add-Member NoteProperty -Name Share -Value ($lookupobjects | ?{$_.Path -eq $object.Path} | select -First 1 -ExpandProperty share)
    }
}
Measure-Command $method1 | select totalseconds

$objects = (0..$numberofobjects) | % {
    New-Object psobject -Property @{'Name'="object$_";'Path'="Path$_"}
}
$lookupobjects = (0..$numberofobjects) | % {
    New-Object psobject -Property @{'Path'="Path$_";'Share'="Share$_"}
}

$method2 = {
    $hash = @{}
    foreach ($obj in $lookupobjects) {
        $hash.($obj.Path) = $obj.share
    }
    foreach ($object in $objects) {
        $object |Add-Member NoteProperty -Name Share -Value ($hash.($object.path)).share
    }
}
Measure-Command $method2 | select totalseconds
Run Code Online (Sandbox Code Playgroud)

博客作者的输出:

TotalSeconds
------------
 167.8825285
   0.7459279
Run Code Online (Sandbox Code Playgroud)

他对代码结果的评论是:

当你把它们放在一起时,你可以看到速度的差异。对象方法在我的计算机上需要 167 秒,而哈希表方法将需要不到一秒的时间来构建哈希表,然后进行查找。

以下是其他一些更微妙的好处: PowerShell 3.0 中的自定义对象默认显示

  • “始终引用重要链接中最相关的部分,以防目标站点无法访问或永久离线。” - http://stackoverflow.com/help/how-to-answer (5认同)
  • 上面的代码除了管道速度慢之外没有证明任何事情。使用此代码作为 method1 ,它比其他代码更快: $method1 = { foreach ($object in $objects) { $value = foreach($lookup in $lookupobjects) { if ($lookup.Path -eq $object.Path) { $lookup.share; $object | 中断 } } 添加成员 NoteProperty -Name Share -Value $value } } (4认同)
  • 好吧,性能 - 好吧。但这就是一切吗?性能也是专业的哈希表。那么 PSCustomObject 有什么存在的权利呢?还有默认显示选项,真的吗?我们经常处理数据——没有人愿意每天都显示这些东西。有时,当我需要显示一些数据时,我仍然可能会构建一个小循环并使用标准格式化程序。似乎不足以为我证明新数据类型的合理性。 (3认同)
  • 第一个链接中的文章没有说明 psobject 与 pscustomobject 的速度。相反,它突出了 O(m*n) 和 O(m*ln n) 算法之间的区别。 (2认同)