web-dev-qa-db-fra.com

Différence entre PSObject, Hashtable et PSCustomObject

Quelqu'un peut-il expliquer les détails? Si je crée un objet en utilisant

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

puis je recherche son type en utilisant getType() PowerShell me dit qu'il est de type Hashtable .

Lors de l'utilisation de Get-Member (alias gm) pour inspecter l'objet, il est évident qu'une table de hachage a été créée, car elle a un keys et un values propriété. Alors, quelle est la différence avec une table de hachage "normale"?

De plus, quel est l'avantage d'utiliser un PSCustomObject? Lorsque vous en créez un en utilisant quelque chose comme ça

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

la seule différence visible pour moi est le type de données différent de PSCustomObject . Au lieu des clés et des propriétés de valeur, une inspection avec gm montre que maintenant chaque clé a été ajoutée en tant qu'objet NoteProperty.

Mais quels avantages ai-je? Je peux accéder à mes valeurs en utilisant ses clés, tout comme dans la table de hachage. Je peux stocker plus que de simples paires clé-valeur (paires clé-objet par exemple) dans PSCustomObject, JUST comme dans la table de hachage. Alors quel est l'avantage? Y a-t-il des différences importantes?

27
masi

Je pense que la plus grande différence que vous verrez est la performance. Jetez un œil à cet article de blog:

Combinaison efficace d'objets - Utilisez une table de hachage pour indexer une collection d'objets

L'auteur a exécuté le code suivant:

$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
#>

Son commentaire concernant les résultats du code est:

Vous pouvez voir la différence de vitesse lorsque vous mettez tout cela ensemble. La méthode objet prend 167 secondes sur mon ordinateur tandis que la méthode de table de hachage prendra moins d'une seconde pour créer la table de hachage et ensuite faire la recherche.

Voici quelques-uns des autres avantages plus subtils: Affichage par défaut des objets personnalisés dans PowerShell 3.

3
Adam Driscoll

Un scénario où [PSCustomObject] est utilisé à la place de HashTable lorsque vous en avez besoin d'une collection. Ce qui suit est d'illustrer la différence dans la façon dont ils sont traités:

$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 entraînera ce qui suit pour $Hash:

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

Et ce qui suit pour $CustomObject:

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

La même chose se produit avec Export-Csv, donc la raison d'utiliser [PSCustomObject] au lieu de simplement HashTable.

29
tkokasih

Disons que je veux créer un dossier. Si j'utilise un PSObject, vous pouvez voir qu'il est faux en le regardant

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

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

Cependant, le PSCustomObject semble correct

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

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

Je peux ensuite diriger l'objet

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

Un avantage que je pense pour PSObject est que vous pouvez créer des méthodes personnalisées avec lui.

Par exemple,

$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()

Vous pouvez l'utiliser pour contrôler l'ordre de tri des propriétés PSObject (voir tri PSObject)

12
Loïc MICHEL

De la documentation PSObject :

Encapsule un objet fournissant des vues alternatives des membres disponibles et des moyens de les étendre. Les membres peuvent être des méthodes, des propriétés, des propriétés paramétrées, etc.

En d'autres termes, un PSObject est un objet auquel vous pouvez ajouter des méthodes et des propriétés après l'avoir créé.

De la documentation "A propos des tables de hachage" :

Une table de hachage, également appelée dictionnaire ou tableau associatif, est une structure de données compacte qui stocke une ou plusieurs paires clé/valeur.

...

Les tables de hachage sont fréquemment utilisées car elles sont très efficaces pour rechercher et récupérer des données.

Vous pouvez utiliser un PSObject comme un Hashtable car PowerShell vous permet d'ajouter des propriétés à PSObjects, mais vous ne devriez pas le faire car vous perdrez l'accès à Hashtable des fonctionnalités spécifiques, telles que les propriétés Keys et Values. En outre, il peut y avoir des coûts de performances et une utilisation supplémentaire de la mémoire.

La documentation PowerShell contient les informations suivantes sur PSCustomObject :

Sert d'espace de base BaseObject lorsque le constructeur de PSObject sans paramètre est utilisé.

Cela n'était pas clair pour moi, mais n post sur un forum PowerShell de le co-auteur d'un certain nombre de livres PowerShell semble plus clair:

[PSCustomObject] est un accélérateur de type. Il construit un PSObject, mais le fait d'une manière qui fait que les clés de table de hachage deviennent des propriétés. PSCustomObject n'est pas un type d'objet en soi - c'est un raccourci de processus. ... PSCustomObject est un espace réservé qui est utilisé lorsque PSObject est appelé sans paramètres de constructeur.

Concernant votre code, @{a=1;b=2;c=3} est un Hashtable. [PSObject]@{a=1;b=2;c=3} ne convertit pas le Hashtable en PSObject ou ne génère pas d'erreur. L'objet reste un Hashtable. Pourtant, [PSCustomObject]@{a=1;b=2;c=3} convertit le Hashtable en PSObject. Je n'ai pas pu trouver de documentation expliquant pourquoi cela se produit.

Si vous souhaitez convertir un Hashtable en un objet afin d'utiliser ses clés comme noms de propriété, vous pouvez utiliser l'une des lignes de code suivantes:

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

# OR

New-Object PSObject -Property @{a=1;b=2;c=3}

# NOTE: Both have the type PSCustomObject

Si vous souhaitez convertir un certain nombre de Hashtables en un objet dont leurs clés sont des noms de propriété, vous pouvez utiliser le code suivant:

@{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
#>

La recherche de documentation concernant NoteProperty a été difficile. Dans le Add-Member documentation , il n'y a pas de -MemberType qui a du sens pour ajouter des propriétés d'objet autres que NoteProperty. Le livre de recettes Windows PowerShell (3e édition) définit le type de membrane Noteproperty comme:

Une propriété définie par la valeur initiale que vous fournissez

  • Lee, H. (2013). Livre de recettes Windows PowerShell . O'Reilly Media, Inc. p. 895.
10
Dave F