51

谁能解释一下细节?如果我使用创建一个对象

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

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

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

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

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

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

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

4

6 回答 6

46

[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

于 2014-05-09T03:10:10.570 回答
35

假设我想创建一个文件夹。如果我使用 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
于 2014-11-11T17:56:34.097 回答
31

PSObject文档中:

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

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

从“关于哈希表”文档

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

...

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

您可以使用 a PSObjectlike a Hashtable,因为 PowerShell 允许您向 中添加属性PSObjects,但您不应该这样做,因为您将无法访问Hashtable特定功能,例如KeysValues属性。此外,可能会有性能成本和额外的内存使用。

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}不会将 转换Hashtable为 aPSObject或生成错误。对象仍然是Hashtable. 但是,[PSCustomObject]@{a=1;b=2;c=3}将 转换HashtablePSObject. 我找不到说明为什么会发生这种情况的文档。

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

[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很难找到有关的文档。Add-Member文档中,-MemberType除了NoteProperty. Windows PowerShell Cookbook (第3 版)将NotepropertyMembertype 定义为:

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

  • 李,H.(2013)。Windows PowerShell 说明书。O'Reilly Media, Inc. p。895。
于 2018-05-06T05:52:12.943 回答
14

我认为 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 排序

于 2013-09-16T19:14:58.980 回答
7

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

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

作者运行如下代码:

$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

博客作者的输出:

TotalSeconds
------------
 167.8825285
   0.7459279

他对代码结果的评论是:

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

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

于 2012-12-23T18:07:38.567 回答
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
}
于 2021-03-13T02:28:47.910 回答