Поделиться через


о_Доступе_К_Членам_Перечисление

Краткое описание

Описывает автоматическое перечисление коллекций при использовании оператора доступа к членам.

Длинное описание

PowerShell поддерживает список типов, которые являются перечисляемыми. Начиная с PowerShell 3.0, функция перечисления членов улучшает удобство использования оператора доступа к членам () для объектов коллекции, которые могут быть перечислены.

Перечисление доступа к членам помогает создавать более простой и короткий код. Вместо подключения объекта коллекции к ForEach-Object или использования встроенного метода ForEach() для доступа к элементам в коллекции можно использовать оператор доступа к члену в объекте коллекции.

В следующих примерах даются одинаковые результаты. В последнем примере показано использование оператора доступа к члену:

PS> Get-Service -Name event* | ForEach-Object -Process { $_.DisplayName }
Windows Event Log
COM+ Event System
PS> (Get-Service -Name event*).ForEach({ $_.DisplayName })
Windows Event Log
COM+ Event System
PS> (Get-Service -Name event*).DisplayName
Windows Event Log
COM+ Event System

Заметка

Оператор доступа к членам можно использовать для получения значений свойства элементов коллекции, но нельзя использовать его для непосредственного задания этих значений. Дополнительную информацию см. в разделе about_Arrays. Перечисление доступа к членам — это удобная функция. Между различными методами перечисления могут быть тонкие различия в поведении и производительности.

При использовании оператора доступа к члену для объекта, и если указанный член существует в этом объекте, вызывается член. При использовании оператора доступа к члену в объекте коллекции, который не имеет указанного элемента, PowerShell перечисляет элементы в этой коллекции и использует оператор доступа к членам для каждого перечисленного элемента.

Во время перечисления доступа к свойствам членов оператор возвращает значение свойства для каждого элемента, у которого есть это свойство. Если у элементов нет указанного свойства, оператор возвращает $null.

Во время перечисления доступа к члену для метода оператор пытается вызвать метод для каждого элемента в коллекции. Если какой-либо элемент в коллекции не имеет указанного метода, оператор возвращает исключение MethodNotFound.

Предупреждение

Во время перечисления доступа к члену для метода метод вызывается для каждого элемента в коллекции. Если вызываемый метод вносит изменения, изменения вносятся для каждого элемента в коллекции. Если во время перечисления возникает ошибка, метод вызывается только в элементах, перечисленных до ошибки. Для дополнительной безопасности рекомендуется вручную пересчитать элементы и явно устранять ошибки.

Доступ к элементам объекта, отличного от перечисления

При использовании оператора доступа к члену в объекте, который не является перечисленной коллекцией, PowerShell вызывает элемент для возврата значения свойства или выходных данных метода для этого объекта.

PS> $MyString = 'abc'
PS> $MyString.Length
3
PS> $MyString.ToUpper()
ABC

При использовании оператора доступа к члену в объекте, отличном от перечисления, который не содержит данного члена, PowerShell возвращает $null для отсутствующего свойства или ошибку MethodNotFound для отсутствующего метода.

PS> $MyString = 'abc'
PS> $null -eq $MyString.DoesNotExist
True
PS> $MyString.DoesNotExist()
InvalidOperation: Method invocation failed because [System.String] does not contain a method named 'DoesNotExist'.

Доступ к членам объекта коллекции

При использовании оператора доступа к члену для объекта коллекции, который имеет члена, всегда возвращается значение свойства или результат метода для объекта коллекции.

Доступ к членам, которые существуют в коллекции, но не к её элементам

В этом примере указанные элементы существуют в коллекции, но не элементы в ней.

PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b')
PS> $Collection.IsReadOnly
False
PS> $Collection.Add('c')
PS> $Collection
a
b
c

Доступ к членам, существующим в коллекции и её элементах

В этом примере указанные члены существуют как в коллекции, так и в ее элементах. Сравните результаты команд, использующих оператор доступа к членам для коллекции, с результатами, полученными при использовании оператора доступа к членам для элементов коллекции в ForEach-Object. В коллекции оператор возвращает значение свойства или результат метода для объекта коллекции, а не элементов в нем.

PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
PS> $Collection.Count
3
PS> $Collection | ForEach-Object -Process { $_.Count }
1
1
1
PS> $Collection.ToString()
System.Collections.Generic.List`1[System.String]
PS> $Collection | ForEach-Object -Process { $_.ToString() }
a
b
c

Заметка

Коллекции, реализующие интерфейс System.Collections.IDictionary, такие как HashTable и OrderedDictionary, имеют другое поведение. При использовании оператора доступа к элементу в словаре, где ключ имеет то же имя, что и свойство, он возвращает значение ключа вместо значения свойства.

Вы можете получить значение свойства объекта словаря с помощью внутреннего члена psbase. Например, если имя ключа keys и вы хотите вернуть коллекцию ключей HashTable, используйте следующий синтаксис:

$hashtable.psbase.Keys

Доступ к членам, которые существуют во всех элементах коллекции, кроме самого элемента.

При использовании оператора доступа к члену для объекта коллекции, в котором нет данного члена, но он имеется у элементов коллекции, PowerShell перечисляет элементы коллекции и возвращает значение свойства или результат метода для каждого элемента.

PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
PS> $Collection.Length
1
1
1
PS> $Collection.ToUpper()
A
B
C

Доступ к членам, которые не существуют в коллекции или её элементах

Если вы используете оператор доступа к члену в объекте коллекции, который не имеет данного члена, и ни один из элементов не обладает им, команда возвращает $null, если указано несуществующее свойство, или ошибку MethodNotFound, если указан несуществующий метод.

PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
PS> $null -eq $Collection.DoesNotExist
True
PS> $Collection.DoesNotExist()
InvalidOperation: Method invocation failed because [System.String] does not
contain a method named 'DoesNotExist'.

Поскольку у объекта коллекции отсутствует член, PowerShell перечислил элементы в коллекции. Обратите внимание, что ошибка MethodNotFound указывает, что System.String не содержит метод, а не System.Collections.Generic.List.

Методы доступа, которые применимы только к некоторым элементам в коллекции

При использовании оператора доступа к члену для доступа к методу в объекте коллекции, который не имеет метода, и только некоторые элементы в коллекции имеют его, команда возвращает ошибку MethodNotFound для первого элемента в коллекции, у которой нет метода. Несмотря на то, что метод вызывается для некоторых элементов, команда возвращает только ошибку.

PS> @('a', 1, 'c').ToUpper()
InvalidOperation: Method invocation failed because [System.Int32] does not
contain a method named 'ToUpper'.

Доступ к свойствам, которые существуют только в некоторых элементах коллекции

При использовании оператора доступа к члену для доступа к свойству объекта коллекции, который не имеет свойства, и только некоторые элементы в коллекции имеют его, команда возвращает значение свойства для каждого элемента коллекции, имеющего свойство.

PS> $CapitalizedProperty = @{
    MemberType = 'ScriptProperty'
    Name       = 'Capitalized'
    Value      = { $this.ToUpper() }
    PassThru   = $true
}
PS> [System.Collections.Generic.List[Object]]$MixedCollection = @(
    'a'
    ('b' | Add-Member @CapitalizedProperty)
    ('c' | Add-Member @CapitalizedProperty)
    'd'
)
PS> $MixedCollection.Capitalized
B
C

Доступ к членам вложенной коллекции

Если перечисленная коллекция содержит вложенную коллекцию, перечисление доступа к членам применяется к каждой вложенной коллекции.

Например, $a представляет собой массив, содержащий два элемента: вложенный массив строк и одну строку.

# Get the count of items in the array.
PS> $a.Count
2
# Get the count of items in each nested item.
PS> $a.GetEnumerator().Count
2
1
# Call the ToUpper() method on all items in the nested array.
PS> $a = @(, ('bar', 'baz'), 'foo')
PS> $a.ToUpper()
BAR
BAZ
FOO

При использовании оператора доступа к членам PowerShell перечисляет элементы в $a и вызывает метод ToUpper() для всех элементов.

Примечания.

Как упоминалось ранее, между различными методами перечисления могут быть тонкие различия в поведении и производительности.

Ошибки приводят к потере выходных данных

Если перечисление доступа к элементу завершается ошибкой, данные из предыдущих успешных вызовов метода не возвращаются. К конечным условиям ошибки относятся:

  • Перечисленный объект не имеет доступа к методу
  • Доступ к методу вызывает завершающееся сообщение об ошибке

Рассмотрим следующий пример:

class Class1 { [Object] Foo() { return 'Bar' } }
class Class2 { [void] Foo() { throw 'Error' } }
class Class3 {}

$example1 = ([Class1]::new(), [Class1]::new())
$example2 = ([Class1]::new(), [Class2]::new())
$example3 = ([Class1]::new(), [Class3]::new())

Оба элемента в $example1 имеют метод Foo(), поэтому вызов метода завершается успешно.

PS> $example1.Foo()
Bar
Bar

Метод Foo() во втором элементе в $example2 вызывает ошибку, поэтому перечисление завершается ошибкой.

PS> $example2.Foo()
Exception:
Line |
   2 |  class Class2 { [void] Foo() { throw 'Error' } }
     |                                ~~~~~~~~~~~~~
     | Error

Второй элемент в $example2 не имеет метода Foo(), поэтому перечисление не удается.

PS> $example3.Foo()
InvalidOperation: Method invocation failed because [Class3] does not contain
a method named 'Foo'.

Сравните это с перечислением с помощью ForEach-Object

PS> $example2 | ForEach-Object -MemberName Foo
Bar
ForEach-Object: Exception calling "Foo" with "0" argument(s): "Error"
PS> $example3 | ForEach-Object -MemberName Foo
Bar

Обратите внимание, что выходные данные показывают успешный вызов Foo() на первом элементе в массиве.

Коллекции, содержащие экземпляры PSCustomObject

Если коллекция объектов содержит экземпляры элементов PSCustomObject, PowerShell неожиданно возвращает значения $null при отсутствии доступного свойства.

В следующих примерах по крайней мере один объект имеет указанное свойство.

PS> $foo = [pscustomobject]@{ Foo = 'Foo' }
PS> $bar = [pscustomobject]@{ Bar = 'Bar' }
PS> $baz = [pscustomobject]@{ Baz = 'Baz' }
PS> ConvertTo-Json ($foo, $bar, $baz).Foo
[
  "Foo",
  null,
  null
]
PS> ConvertTo-Json ((Get-Process -Id $PID), $foo).Name
[
  "pwsh",
  null
]

Вы ожидаете, что PowerShell вернет один объект для элемента с указанным свойством. Вместо этого PowerShell также возвращает значение $null для каждого элемента, у которых нет свойства.

Дополнительные сведения об этом поведении см. в статье о проблеме PowerShell #13752.

См. также