about_Member-Access_Enumeration
Breve descrição
Descreve a enumeração automática de coleções ao usar o operador member-access.
Descrição longa
O PowerShell mantém uma lista de tipos enumeráveis. A partir do PowerShell 3.0, o recurso de enumeração de acesso de membro melhora a conveniência de usar o operador de acesso de membro (.
) em objetos de coleção que são enumeráveis.
A enumeração de acesso de membro ajuda você a escrever código mais simples e mais curto. Em vez de canalizar um objeto de coleção para ForEach-Object
ou usar o ForEach()
método intrínseco para acessar membros em cada item da coleção, você pode usar o operador member-access no objeto de coleção.
Os exemplos a seguir produzem os mesmos resultados. O último exemplo demonstra o uso do operador member-access:
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
Nota
Você pode usar o operador de acesso de membro para obter os valores de uma propriedade em itens de uma coleção, mas não pode usá-lo para defini-los diretamente. Para obter mais informações, consulte about_Arrays. A enumeração de acesso de membro é um recurso de conveniência. Pode haver diferenças sutis de comportamento e desempenho entre os vários métodos de enumeração.
Quando você usa o operador member-access em um objeto e o membro especificado existe nesse objeto, o membro é invocado. Quando você usa o operador de acesso de membro em um objeto de coleção que não tem o membro especificado, o PowerShell enumera os itens nessa coleção e usa o operador de acesso de membro em cada item enumerado.
Durante a enumeração de acesso de membro para uma propriedade, o operador retorna o valor da propriedade para cada item que tem essa propriedade. Se nenhum item tiver a propriedade especificada, o operador retornará $null
.
Durante a enumeração de acesso de membro para um método, o operador tenta chamar o método em cada item da coleção. Se qualquer item na coleção não tiver o método especificado, o operador retornará a exceção MethodNotFound .
Aviso
Durante a enumeração de acesso de membro para um método, o método é chamado em cada item da coleção. Se o método que você está chamando fizer alterações, as alterações serão feitas para cada item da coleção. Se ocorrer um erro durante a enumeração, o método é chamado somente nos itens enumerados antes do erro. Para maior segurança, considere enumerar manualmente os itens e manipular explicitamente quaisquer erros.
Aceder aos membros de um objeto não enumerável
Quando você usa o operador de acesso de membro em um objeto que não é uma coleção enumerável, o PowerShell invoca o membro para retornar o valor da propriedade ou saída do método para esse objeto.
PS> $MyString = 'abc'
PS> $MyString.Length
3
PS> $MyString.ToUpper()
ABC
Quando você usa o operador de acesso de membro em um objeto não enumerável que não tem o membro, o PowerShell retorna
PS> $MyString = 'abc'
PS> $null -eq $MyString.DoesNotExist
True
PS> $MyString.DoesNotExist()
Method invocation failed because [System.String] does not contain a method named 'DoesNotExist'.
At line:1 char:1
+ $MyString.DoesNotExist()
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Acessar membros de um objeto de coleção
Quando você usa o operador member-access em um objeto de coleção que tem o membro, ele sempre retorna o valor da propriedade ou o resultado do método para o objeto de coleção.
Acessar membros que existem na coleção, mas não seus itens
Neste exemplo, os membros especificados existem na coleção, mas não os itens nela.
PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b')
PS> $Collection.IsReadOnly
False
PS> $Collection.Add('c')
PS> $Collection
a
b
c
Acessar membros que existem na coleção e seus itens
Neste exemplo, os membros especificados existem na coleção e nos itens nela. Compare os resultados dos comandos usando o operador member-access na coleção com os resultados do uso do member-access operator nos itens de coleção no ForEach-Object
. Na coleção, o operador retorna o valor da propriedade ou o resultado do método para o objeto de coleção e não os itens nele.
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
Nota
As coleções que implementam a interface System.Collections.IDictionary , como HashTable e OrderedDictionary, têm um comportamento diferente. Quando você usa o operador de acesso de membro em um dicionário que tem uma chave com o mesmo nome de uma propriedade, ele retorna o valor da chave em vez do da propriedade.
Você pode acessar o valor da propriedade do objeto de dicionário com o membro intrínseco psbase. Por exemplo, se o nome da chave for keys
e você quiser retornar a coleção das chaves HashTable , use esta sintaxe:
$hashtable.psbase.Keys
Aceder a membros que existem em todos os elementos de uma coleção, mas não no próprio elemento
Quando usa o operador de acesso a membro num objeto de coleção que não tem o membro, mas os itens que estão nele têm, o PowerShell enumera os itens na coleção e devolve para cada item o valor da propriedade ou o resultado do método.
PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
PS> $Collection.Length
1
1
1
PS> $Collection.ToUpper()
A
B
C
Acessar membros que não existem na coleção ou em seus itens
Quando você usa o operador member-access em um objeto de coleção que não tem o membro e nem os itens nele, o comando retorna $null
se você especificar uma propriedade ou um erro MethodNotFound
se especificar um método.
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'.
Como o objeto de coleção não tem o membro, o PowerShell enumerou os itens na coleção. Observe que o erro MethodNotFound especifica que System.String não contém o método, em comparação com System.Collections.Generic.List.
Métodos de acesso que existem apenas em alguns itens de uma coleção
Quando você usa o operador member-access para acessar um método em um objeto de coleção que não tem o método e apenas alguns itens na coleção o têm, o comando retorna um erro MethodNotFound
para o primeiro item da coleção que não tem o método. Mesmo que o método seja chamado em alguns itens, o comando retorna apenas o erro.
PS> @('a', 1, 'c').ToUpper()
InvalidOperation: Method invocation failed because [System.Int32] does not
contain a method named 'ToUpper'.
Acessar propriedades que existem apenas em alguns itens de uma coleção
Quando você usa o operador de acesso de membro para acessar uma propriedade em um objeto de coleção que não tem a propriedade e apenas alguns itens na coleção a têm, o comando retorna o valor da propriedade para cada item da coleção que tem a propriedade.
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
Aceder a membros de uma coleção aninhada
Quando uma coleção enumerável contém uma coleção aninhada, a enumeração de acesso de membro é aplicada a cada coleção aninhada.
Por exemplo, $a
é uma matriz que contém dois elementos: uma matriz aninhada de cadeias de caracteres e uma única cadeia de caracteres.
# 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
Quando você usa o operador de acesso de membro, o PowerShell enumera os itens em $a
e chama o método ToUpper()
em todos os itens.
Observações
Como dito anteriormente, pode haver diferenças sutis de comportamento e desempenho entre os vários métodos de enumeração.
Erros resultam em perda na produção.
Quando a enumeração de acesso de membro é encerrada por um erro, a saída de chamadas de método bem-sucedidas anteriores não é retornada. As condições de erro de encerramento incluem:
- o objeto enumerado não tem o método acessado
- O método acessado gera um erro de encerramento
Considere o seguinte exemplo:
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())
Ambos os itens no $example1
têm o método Foo()
, portanto, a chamada de método é bem-sucedida.
PS> $example1.Foo()
Bar
Bar
O método Foo()
no segundo item em $example2
gera um erro, portanto, a enumeração falha.
PS> $example2.Foo()
Exception:
Line |
2 | class Class2 { [void] Foo() { throw 'Error' } }
| ~~~~~~~~~~~~~
| Error
O segundo item em $example2
não tem o método Foo()
, portanto, a enumeração falha.
PS> $example3.Foo()
InvalidOperation: Method invocation failed because [Class3] does not contain
a method named 'Foo'.
Compare isso com a enumeração usando 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
Observe que a saída mostra a chamada bem-sucedida executada para Foo()
no primeiro item da matriz.
Coleções contendo instâncias PSCustomObject
Se a coleção de objetos contiver instâncias de itens PSCustomObject, o PowerShell inesperadamente retorna $null
valores quando a propriedade acessada estiver ausente.
Nos exemplos a seguir, pelo menos um objeto tem a propriedade referenciada.
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
]
Você esperaria que o PowerShell retornasse um único objeto para o item que tem a propriedade especificada. Em vez disso, o PowerShell também retorna um valor $null
para cada item que não tem a propriedade.
Para obter mais informações sobre esse comportamento, consulte PowerShell Issue #13752.