PowerShell / PowerShell/PSScriptAnalyzer
rule request: AvoidPlusEqualToPopulateDictionary
Personne n'a encore pris cette issue.
- Langage dominant
- C#
- Étoiles
- 2.2k
- Forks
- 414
- Merge moyen
- 13 h 1 min
- PR mergées (30 j)
- 2
Description
Avoid assignment by addition operator (+=) to populate a dictionary
As with using the assignment by addition operator (+=) to build a collection or a string, populating a dictionary using the assignment by addition operator (+=) is in effective:
Tests
$tests = @{
'Array+=' = {
param($count)
$result = @()
foreach($i in 1..$count) {
$result += $i
}
}
'IList.Add' = {
param($count)
$result = [Collections.Generic.List[int]]::new()
foreach($i in 1..$count) {
$result.Add($i)
}
}
'IList+=' = {
param($count)
$result = [Collections.Generic.List[int]]::new()
foreach($i in 1..$count) {
$result += $i
}
}
'IDictionary[]' = {
param($count)
$result = @{}
foreach($i in 1..$count) {
$result[$i] = $i
}
}
'IDictionary.Add' = {
param($count)
$result = @{}
foreach($i in 1..$count) {
$result.Add($i, $i)
}
}
'IDictionary+=' = {
param($count)
$result = @{}
foreach($i in 1..$count) {
$result += @{ $i = $i }
}
}
} # Tests
1kb, 5kb, 10kb | ForEach-Object {
$groupResult = foreach($test in $tests.GetEnumerator()) {
$ms = (Measure-Command { & $test.Value -Count $_ }).TotalMilliseconds
[pscustomobject]@{
CollectionSize = $_
Test = $test.Key
TotalMilliseconds = [Math]::Round($ms, 2)
}
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}
$groupResult = $groupResult | Sort-Object TotalMilliseconds
$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
$speed = [Math]::Round($relativeSpeed, 2).ToString() + 'x'
if ($speed -eq '1x') { $speed } else { $speed + ' slower' }
}
} | Format-Table -AutoSize
}
CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
1024 IDictionary[] 0.19 1x
1024 IList.Add 0.35 1.84x slower
1024 IDictionary.Add 0.50 2.63x slower
1024 Array+= 0.74 3.89x slower
1024 IList+= 1.16 6.11x slower
1024 IDictionary+= 39.17 206.16x slower
CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
5120 IDictionary[] 0.71 1x
5120 IDictionary.Add 1.41 1.99x slower
5120 IList.Add 1.50 2.11x slower
5120 IList+= 20.33 28.63x slower
5120 Array+= 21.51 30.3x slower
5120 IDictionary+= 1880.89 2649.14x slower
CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
10240 IDictionary[] 0.92 1x
10240 IDictionary.Add 3.79 4.12x slower
10240 IList.Add 4.71 5.12x slower
10240 IList+= 71.91 78.16x slower
10240 Array+= 86.93 94.49x slower
10240 IDictionary+= 5502.40 5980.87x slower
Instead use (even for a single item):
- the square bracket syntax (
$Dictionary[$Key] = $Value) or dot syntax ($Dictionary.$Key = $Value) which will overwrite any duplicate key - the
.Add()method ($Dictionary($Key, $Value)) which returns an error when the key already exists
Proposed technical implementation details (optional)
As apposed to the requests for avoiding the assignment by addition operator (+=) to build a collection or a string, the majority of this bad practice syntax would be easier to capture:
- Check for the
+=operator - Directly followed by a hash table syntax
@{ ... }- With a single key-value pair
- And a dynamic key
Even using a simple search string will capture lot of issues (note that almost all results are embedded in a foreach loop):
https://github.com/search?q=language%3Apowershell+%22%2b=%20@%7B%20$%22&type=code
The LHS could still be anything else than a presumed IDictionary, e.g. an IList.
But than there is still a good reason to avoid the += operator...
What is the latest version of PSScriptAnalyzer at the point of writing
1.24.0
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
L’issue ne nomme aucun fichier d’implémentation ni aucun test. Commencez par localiser les règles existantes pour += et leurs modèles de test, puis vérifiez comment une règle distinguerait += suivi d’une table de hachage à entrée unique avec une clé dynamique. Le travail est terminé lorsque la nouvelle règle signale la forme ciblée de remplissage du dictionnaire tout en conservant les alternatives documentées avec crochets, point et Add.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- csharp, powershell
- Domaine
- devtools, tooling
- Type d'issue
- Fonctionnalité
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 45/100