about_Member-Access_Enumeration
简短说明
介绍使用成员访问运算符时列表集合项的自动枚举。
长说明
从 PowerShell 3.0 开始,成员访问枚举功能可提高对列表集合对象使用成员访问运算符 (.
) 的便利性。 使用成员访问运算符访问集合上不存在的成员时,PowerShell 会自动枚举集合中的项,并尝试访问每个项上的指定成员。
成员访问枚举可帮助你编写更简单、更短的代码。 可以对集合对象使用成员访问运算符,而不是通过管道将集合对象传递到 ForEach-Object
或使用 ForEach()
内部方法访问集合中每个项上的成员。
这些命令在功能上与演示成员访问运算符用法的最后一个命令相同:
Get-Service -Name event* | ForEach-Object -Process { $_.DisplayName }
(Get-Service -Name event*).ForEach({ $_.DisplayName })
(Get-Service -Name event*).DisplayName
Windows Event Log
COM+ Event System
Windows Event Log
COM+ Event System
Windows Event Log
COM+ Event System
注意
可以使用成员访问运算符获取集合中项的属性值,但不能使用它来直接设置这些值。 有关详细信息,请参阅 about_Arrays。
对任何对象使用成员访问运算符且该对象上存在指定的成员时,将调用该成员。 对于属性成员,运算符会返回该属性的值。 对于方法成员,运算符会对对象调用该方法。
当你对没有指定成员的列表集合对象使用成员访问运算符时,PowerShell 会自动枚举该集合中的项,并对每个枚举的项使用成员访问运算符。
可通过查看对象类型是否实现 IList 接口来检查对象是否为列表集合:
$List = @('a', 'b')
$Hash = @{ a = 'b' }
$List.GetType().ImplementedInterfaces.Name -contains 'IList'
$Hash.GetType().ImplementedInterfaces.Name -contains 'IList'
True
False
在属性的成员访问枚举期间,运算符会返回具有该属性的每个项的属性值。 如果没有项具有指定属性,则运算符返回 $null
。
在方法的成员访问枚举期间,运算符会尝试对集合中的每个项调用该方法。 如果集合中的任何项没有指定的方法,运算符将 返回 MethodNotFound 异常。
警告
在方法的成员访问枚举期间,会对集合中的每个项调用该方法。 如果要调用的方法发生变化,则会针对集合中的每个项进行更改。 如果在枚举期间发生错误,则仅对出错之前枚举的项调用该方法。 为了提高安全性,请考虑手动枚举项并显式处理任何错误。
以下示例详细介绍了成员访问运算符在所有可能的情况下的行为。
访问非列表对象的成员
在不是列表集合且具有成员的对象上使用成员访问运算符时,该命令会返回该对象的属性值或方法输出。
$MyString = 'abc'
$MyString.Length
$MyString.ToUpper()
3
ABC
在不包含成员的非列表对象上使用成员访问运算符时,如果指定属性,则命令返回 $null
;如果指定方法,则命令返回 MethodNotFound 错误。
$MyString = 'abc'
$null -eq $MyString.DoesNotExist
$MyString.DoesNotExist()
True
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
访问列表集合对象的成员
对具有成员的集合对象使用成员访问运算符时,它始终返回集合对象的属性值或方法结果。
访问集合中存在但集合的项中不存在的成员
在此示例中,指定的成员存在于集合中,但不存在于集合的项中。
[System.Collections.Generic.List[string]]$Collection = @('a', 'b')
$Collection.IsReadOnly
$Collection.Add('c')
$Collection
False
a
b
c
访问集合及其项中存在的成员
在此示例中,指定的成员既存在于集合中,又存在于集合的项中。 将对集合使用成员访问运算符的命令的结果与对 ForEach-Object
中的集合项使用成员访问运算符的结果进行比较。 在集合中,运算符返回集合对象的属性值或方法结果,而不返回其中的项。
[System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
$Collection.Count
$Collection | ForEach-Object -Process { $_.Count }
$Collection.ToString()
$Collection | ForEach-Object -Process { $_.ToString() }
3
1
1
1
System.Collections.Generic.List`1[System.String]
a
b
c
注意
实现 System.Collections.IDictionary 接口的集合(如 HashTable 和 OrderedDictionary)具有不同的行为。 对键名与属性名相同的字典使用成员访问运算符时,它会返回键的值,而不返回属性的值。
可以使用 psbase 内部成员访问字典对象的属性值。 例如,如果键名为 keys
并且你想要返回 HashTable 键的集合,请使用以下语法:
$hashtable.PSBase.Keys
访问集合中的所有项上存在但集合中没有的成员
当对自身没有成员但其中的项有成员的集合对象使用成员访问运算符时,PowerShell 会枚举集合中的项,并返回每个项的属性值或方法结果。
[System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
$Collection.Length
$Collection.ToUpper()
1
1
1
A
B
C
访问在集合及其项中均不存在的成员
在自身没有成员且其中的项也没有成员的集合对象上使用成员访问运算符时,如果指定属性,则命令返回 $null
;如果指定方法,则命令返回 MethodNotFound
。
[System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
$null -eq $Collection.DoesNotExist
$Collection.DoesNotExist()
True
Method invocation failed because [System.String] does not contain a method
named 'DoesNotExist'.
At line:1 char:1
+ $Collection.DoesNotExist()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
集合对象没有成员,因此 PowerShell 会枚举集合中的项。 请注意,MethodNotFound 错误指定 System.String 不包含该方法,而是包含 System.Collections.Generic.List。
访问仅存在于集合中的某些项上的方法
使用成员访问运算符来访问自身没有方法(只有集合中的某些项有方法)的集合对象上的方法时,该命令对集合中没有方法的第一个项返回 MethodNotFound
错误。 即使对某些项调用此方法,该命令也仅返回该错误。
@('a', 1, 'c').ToUpper()
Method invocation failed because [System.Int32] does not contain a method
named 'ToUpper'.
At line:1 char:1
+ @('a', 1, 'c').ToUpper()
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
访问仅存在于集合中的某些项上的属性
使用成员访问运算符来访问自身没有属性(只有集合中的某些项有属性)的集合对象上的属性时,该命令会返回集合中有属性的每个项的属性值。
$CapitalizedProperty = @{
MemberType = 'ScriptProperty'
Name = 'Capitalized'
Value = { $this.ToUpper() }
PassThru = $true
}
[System.Collections.Generic.List[object]]$MixedCollection = @(
'a'
('b' | Add-Member @CapitalizedProperty)
('c' | Add-Member @CapitalizedProperty)
'd'
)
$MixedCollection.Capitalized
B
C