Разница между PSObject, Hashtable и PSCustomObject
Кто-нибудь может объяснить детали? Если я создаю объект, используя
$var = [PSObject]@{a=1;b=2;c=3}
и затем я ищу его тип, используя getType()
PowerShell говорит мне его типа Hashtable.
При использовании Get-Member (alias gm
) для проверки объекта очевидно, что хэш-таблица была создана, так как она имеет keys
и свойство values
. Итак, какая разница с "нормальной" хэш-таблицей?
Кроме того, какое преимущество использования PSCustomObject? Создавая один, используя что-то вроде этого
$var = [PSCustomObject]@{a=1;b=2;c=3}
единственная видимая разница для меня - это другой тип данных PSCustomObject. Также вместо свойств ключей и значений проверка с помощью gm
показывает, что теперь каждый ключ был добавлен как объект NoteProperty.
Но какие у меня преимущества? Я могу получить доступ к своим значениям, используя его ключи, как в хэш-таблице. Я могу хранить больше, чем простые пары ключ-значение (например, пары "ключ-объект") в PSCustomObject, JUST, как в хеш-таблице. Итак, какое преимущество? Есть ли какие-то важные отличия?
Ответы
Ответ 1
Я думаю, что самая большая разница, которую вы увидите, - это производительность. Взгляните на это сообщение в блоге:
Эффективное объединение объектов - используйте таблицу хэшей для индексации коллекции объектов
Автор выполнил следующий код:
$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 output:
TotalSeconds
------------
167.8825285
0.7459279
#>
Его комментарий относительно результатов кода:
Вы можете видеть разницу в скорости, когда вы все вместе. Метод объекта занимает 167 секунд на моем компьютере, в то время как метод хеш-таблицы займет менее секунды, чтобы построить хэш-таблицу, а затем выполнить поиск.
Вот некоторые из других, более тонких преимуществ: отображение пользовательских объектов по умолчанию в PowerShell 3.0
Ответ 2
Один сценарий, когда [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
.
Ответ 3
Скажем, я хочу создать папку. Если я использую 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
Ответ 4
Одно из преимуществ, которое, как мне кажется, для 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)
Ответ 5
Из документации PSObject
:
Оборачивает объект, предоставляя альтернативные представления о доступных членах и способах их расширения. Членами могут быть методы, свойства, параметризованные свойства и т.д.
Другими словами, PSObject
- это объект, к которому можно добавить методы и свойства после того, как вы его создали.
Из документации "О хеш-таблицах":
Хеш-таблица, также известная как словарь или ассоциативный массив, представляет собой компактную структуру данных, в которой хранится одна или несколько пар ключ/значение.
...
Хеш-таблицы часто используются, потому что они очень эффективны для поиска и извлечения данных.
Вы можете использовать PSObject
как Hashtable
потому что PowerShell позволяет вам добавлять свойства к PSObjects
, но вы не должны этого делать, потому что вы потеряете доступ к определенным функциям Hashtable
, таким как свойства Keys
и Values
. Кроме того, могут быть затраты производительности и использование дополнительной памяти.
Документация PowerShell содержит следующую информацию о PSCustomObject
:
Служит заполнителем BaseObject, когда используется конструктор PSObject без параметров.
Это было неясно для меня, но пост на форуме PowerShell от соавтора ряда книг по PowerShell кажется более ясным:
[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
было сложно. В документации Add-Member
нет -MemberType
который имеет смысл добавлять свойства объекта, кроме NoteProperty
. Поваренная книга Windows PowerShell (3-е издание) определила Noteproperty
члена Noteproperty следующим образом:
Свойство, определенное начальным значением, которое вы предоставляете
- Lee, H. (2013). Поваренная книга Windows PowerShell. O'Reilly Media, Inc. с. +895.