有人可以解释一下细节吗?如果我使用
创建一个对象$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中存储多个简单的键值对(例如键对象对),就像在哈希表中一样。那有什么好处?有什么重要的区别吗?
答案 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
特定功能,例如Keys
和Values
属性。此外,可能会有性能成本和额外的内存使用量。
The PowerShell documentation has the following information about PSCustomObject
:
当使用PSObject的没有参数的构造函数时,将其用作占位符BaseObject。
我不清楚这一点,但来自a post on a PowerShell forum的the 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
}