ArrayList .Add vs .AddRange по отношению к конвейеру - PullRequest
1 голос
/ 02 мая 2020

При правильно определенной переменной

$test = New-Object System.Collections.ArrayList

.Add загрязняет конвейер количеством элементов в массиве, а .AddRange - нет. $test.Add('Single') сбросит счетчик на консоль. $test.AddRange(@('Single2')) будет чистым без лишних усилий. Почему разное поведение? Это просто недосмотр или есть какое-то преднамеренное поведение, которого я не понимаю?

Учитывая, что .AddRange требует принуждения к массиву, когда не используется переменная (которая уже является массивом), я склоняюсь к использованию [void]$variable.Add('String') когда я знаю, что мне нужно добавить только один элемент, и [void]$test.AddRange($variable), когда я добавляю массив в массив, даже когда $variable содержит или может содержать только один элемент. [void] здесь не требуется, но мне интересно, будет ли это лучше всего иметь, в зависимости, конечно, от ответа выше. Или я что-то там тоже пропускаю?

Ответы [ 2 ]

1 голос
/ 03 мая 2020

Почему другое поведение? Это просто недосмотр или есть какое-то намеренное поведение, которого я не понимаю?

Потому что много лет go кто-то решил вот так ArrayList должен себя вести!

Add() возвращает индекс, по которому аргумент был вставлен в список, что действительно может быть полезно и имеет смысл.

С другой стороны, AddRange() не сразу понятно, почему он должен что-либо возвращать, и если да, что ? Индекс элемента first во входных аргументах? последний ? Или он должен возвращать массив переменного размера со всеми индексами вставки? Это было бы неловко! Поэтому, кто бы ни внедрил ArrayList, он решил вообще ничего не возвращать.

В C# или VB.NET, для которых изначально был разработан ArrayList, "загрязнение трубопровода" на самом деле не существует как Согласно этой концепции, среда выполнения просто не будет копировать возвращаемое значение обратно вызывающей стороне, если кто-то вызывает .Add() без присвоения переменной.

[void] здесь не требуется, но мне интересно, это просто лучшая практика иметь его, в зависимости, конечно, от ответа выше. Или я что-то там тоже пропускаю?

Нет, это совершенно не нужно. AddRange() не волшебным образом однажды изменится на вывод чего-либо.


Если вам никогда не нужно знать индекс вставки, используйте вместо него [System.Collections.Generic.List[psobject]]:

$list = [System.Collections.Generic.List[psobject]]::new()

# this won't return anything, no need for `[void]`
$list.Add(123)

Если по какой-то причине вы должны использовать ArrayList, вы можете "замолчать", переопределив метод Add():

function New-SilentArrayList {
  # Create a new ArrayList
  $newList = [System.Collections.ArrayList]::new()

  # Create a new `Add()` method, then return the list
  $newAdd  = @{
    InputObject = $newList
    MemberType = 'ScriptMethod' 
    Name = 'Add'
    Value = {param($obj) $this.AddRange(@($obj))}
  }
  Write-Output $( 
    Add-Member @newAdd -Force -PassThru
  ) -NoEnumerate
}

Теперь ваши ArrayList Add() никогда больше не будут пискать!

PS C:\> $list = New-SilentArrayList
PS C:\> $list.Add(123)
PS C:\> $list
123
1 голос
/ 02 мая 2020

Очевидно, я не совсем понял, куда вы направляетесь.
" Добавление загрязняет конвейер ", на секунду подумал, что это правильное утверждение , но . Net такие методы, как $variable.Add('String') , не не используют конвейер PowerShell сам по себе ( до момента вывода массива с помощью команды Write-Output , которая является командой по умолчанию, если вы не назначаете ее переменной).

Командлет Write-Output обычно используется в сценариях для отображения строк и других объектов на консоли. Однако из-за поведения по умолчанию отображение объектов в конце конвейера обычно не требует использования командлета.

Дело в том, что Add метод ArrayList возвращает [Int32] " Индекс ArrayList, при котором было добавлено значение ", а AddRange ничего не возвращает , Это означает, что если вы не назначите результаты чему-либо другому (включая $Null = $test.Add('Single')), они действительно будут выводиться в конвейер PowerShell.
Вместо этого вы можете также рассмотреть возможность использования метода Add класса List, который также ничего не возвращает, см. также: ArrayList vs List <> в C#.
Но в целом я рекомендую использовать встроенные команды PowerShell, которые используют конвейер
(я не могу дать вам хороший пример, так как не ясно, какой вывод вы ожидаете, но я заметил еще один вопрос, который вы удалили, и из этого вопроса я предполагаю, что этот Почему я не должен использовать оператор присваивания увеличения (+ =) для создания коллекции ответ может помочь вам в дальнейшем)

...