Разница между PSObject, Hashtable и PSCustomObject - программирование
Подтвердить что ты не робот

Разница между 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, как в хеш-таблице. Итак, какое преимущество? Есть ли какие-то важные отличия?

4b9b3361

Ответ 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.