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?
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.
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
.
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
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)
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.