PSObject,Hashtable和PSCustomObject之间的区别

时间:2012-12-23 16:52:25

标签: powershell powershell-v3.0 psobject

有人可以解释一下细节吗?如果我使用

创建一个对象
$var = [PSObject]@{a=1;b=2;c=3}

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

使用Get-Member(别名gm)检查对象时,很明显已创建哈希表,因为它具有keysvalues属性。那么“普通”散列表的区别是什么?

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

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

唯一可见的区别是 PSCustomObject 的不同数据类型。另外,使用gm进行检查,而不是键和值属性,显示现在每个键都已添加为NoteProperty对象。

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

6 个答案:

答案 0 :(得分:26)

使用[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

Format-Table将导致以下$Hash

Name    Value
----    -----
Name    Object 1
Squared 1
Index   1
Name    Object 2
Squared 4
Index   2
Name    Object 3
Squared 9
...

以下$CustomObject

Name      Index Squared
----      ----- -------
Object 1      1       1
Object 2      2       4
Object 3      3       9
Object 4      4      16
Object 5      5      25
...

同样的事情发生在Export-Csv上,因此使用[PSCustomObject]而非普通HashTable的原因。

答案 1 :(得分:15)

说我想创建一个文件夹。如果我使用PSObject,你可以告诉它错了 看着它

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

Name                           Value
----                           -----
Path                           foo
Type                           directory

然而,PSCustomObject看起来是正确的

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

Path                                    Type
----                                    ----
foo                                     directory

然后我可以管道对象

[PSCustomObject] @{Path='foo'; Type='directory'} | New-Item

答案 2 :(得分: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()

您可以使用它来控制PSObject属性的排序顺序(参见 PSObject sorting

答案 3 :(得分:8)

From the PSObject documentation

  

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

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

From the "About Hash Tables" documentation

  

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

     

...

     

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

您可以像PSObject一样使用Hashtable,因为PowerShell允许您向PSObjects添加属性,但您不应该这样做,因为您将失去访问权限至Hashtable特定功能,例如KeysValues属性。此外,可能会有性能成本和额外的内存使用量。

The PowerShell documentation has the following information about PSCustomObject

  

当使用PSObject的没有参数的构造函数时,将其用作占位符BaseObject。

我不清楚这一点,但来自a post on a PowerShell forumthe co-author of a number of PowerShell books似乎更清楚:

  

[PSCustomObject]是一种类型加速器。它构造一个PSObject,但这样做会导致哈希表键成为属性。 PSCustomObject本身并不是对象类型 - 它是一个进程快捷方式。 ... PSCustomObject是在没有构造函数参数的情况下调用PSObject时使用的占位符。

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

如果要将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

如果要将多个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
#>

查找有关NoteProperty的文档很困难。 In the Add-Member documentation,除了-MemberType之外,没有任何NoteProperty有助于添加对象属性。 Windows PowerShell Cookbook (第3版)将Noteproperty Membertype定义为:

  

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

     
      
  • Lee,H。(2013)。 Windows PowerShell Cookbook 。 O&#39; Reilly Media,Inc。p。 895。
  •   

答案 4 :(得分:3)

我认为你看到的最大的不同是性能。看看这篇博文:

Combining Objects Efficiently – Use a Hash Table to Index a Collection of Objects

作者运行了以下代码:

$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

<#
Blog author's output:

TotalSeconds
------------
 167.8825285
   0.7459279
#>

他对代码结果的评论是:

  

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

以下是一些其他更微妙的好处: Custom objects default display in PowerShell 3.0

答案 5 :(得分:0)

我们的 Windows-PKI 中有一堆模板,我们需要一个脚本,该脚本必须与所有活动模板一起使用。我们不需要动态添加模板或删除它们。 对我来说完美的(因为它读起来也很“自然”)如下:

$templates = @(
    [PSCustomObject]@{Name = 'template1'; Oid = '1.1.1.1.1'}
    [PSCustomObject]@{Name = 'template2'; Oid = '2.2.2.2.2'}
    [PSCustomObject]@{Name = 'template3'; Oid = '3.3.3.3.3'}
    [PSCustomObject]@{Name = 'template4'; Oid = '4.4.4.4.4'}
    [PSCustomObject]@{Name = 'template5'; Oid = '5.5.5.5.5'}
)

foreach ($template in $templates)
{
   Write-Output $template.Name $template.Oid
}