gpt4 book ai didi

arrays - 没有 '.Count'属性的对象-使用@()(数组子表达式运算符)与[Array]类型转换

转载 作者:行者123 更新时间:2023-12-04 14:09:10 28 4
gpt4 key购买 nike

我正在尝试执行一些简单的if语句,但是所有基于[Microsoft.Management.Infrastructure.CimInstance]的较新cmdlet似乎都没有公开.count方法?

$Disks = Get-Disk
$Disks.Count

不返回任何东西。我发现可以将其强制转换为[array],从而使其按预期返回.NET .count方法。
[Array]$Disks = Get-Disk
$Disks.Count

无需将其直接转换为以前的cmdlet的数组即可使用:
(Get-Services).Count

建议的解决方法是什么?

一个不起作用的示例:
$PageDisk = Get-Disk | Where {($_.IsBoot -eq $False) -and ($_.IsSystem -eq $False)}
If ($PageDisk.Count -lt 1) {Write-Host "No suitable drives."; Continue}
Else If ($PageDisk.Count -gt 1) {Write-Host "Too many drives found, manually select it."}
Else If ($PageDisk.Count -eq 1) { Do X }

选项A(以数组形式广播):
[Array]$PageDisk = Get-Disk | Where {($_.IsBoot -eq $False) -and ($_.IsSystem -eq $False)}
If ($PageDisk.Count -lt 1) {Write-Host "No suitable drives."; Continue}
Else If ($PageDisk.Count -gt 1) {Write-Host "Too many drives found, manually select it."}
Else If ($PageDisk.Count -eq 1) { Do X }

选项B(使用数组索引):
 $PageDisk = Get-Disk | Where {($_.IsBoot -eq $False) -and ($_.IsSystem -eq $False)}
If ($PageDisk[0] -eq $Null) {Write-Host "No suitable drives."; Continue}
Else If ($PageDisk[1] -ne $Null) {Write-Host "Too many drives found, manually select it."}
Else If (($PageDisk[0] -ne $Null) -and (PageDisk[1] -eq $Null)) { Do X }

选项C(数组)-感谢@PetSerAl:
$PageDisk = @(Get-Disk | Where {($_.IsBoot -eq $False) -and ($_.IsSystem -eq $False)})
If ($PageDisk.Count -lt 1) {Write-Host "No suitable drives."; Continue}
Else If ($PageDisk.Count -gt 1) {Write-Host "Too many drives found, manually select it."}
Else If ($PageDisk.Count -eq 1) { Do X }

基于CIM的cmdlet不公开.Count方法的原因是什么?建议的处理方式是什么?选项B在我看来是令人费解的,而且很难阅读。选项A可行,但是powershell难道不应该将它强制转换为数组吗?我会以完全错误的方式进行此操作吗?

最佳答案

在PSv3 +中,通过统一处理标量和集合,任何对象-甚至$null-都应具有.Count属性(并且,除了$null之外,还应支持使用[0]进行索引)。

如果出现任何不支持上述内容的对象,则应视为错误。

例如,未按这些规则播放的[pscustomobject]实例就是known bug

由于我不知道上述错误是否与[Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/Storage/MSFT_Disk]输出的Get-Disk实例有关,并且由于Get-Disk(至少当前)仅在Windows PowerShell中可用,因此建议您在uservoice.com上提交单独的错误。

仅在必要时使用数组子表达式运算符@(...) :

  • 作为上述错误的解决方法
  • 如果标量对象碰巧具有自己的 .Count属性,则为


  • 通常为,如果确实需要确保某些东西是数组,则使用@(...)而不是[Array] ... / [object[]] ... -@()是PowerShell惯用语,更加简洁,从语法上更简单。

    就是说,鉴于@()技术上会创建现有数组的(浅)副本,因此在处理潜在的大型数组时,您可能更喜欢[Array]

    另外, @(...)[Array] ...通常不等同于,就像PetSerAl在对该问题的评论中的有用示例所示;改编他的例子之一:
    @($null)返回一个单项数组,其唯一元素是$null,而[Array] $null不起作用(保持$null)。
    @()的这种行为与其目的一致(请参见下文):由于$null不是数组,因此@()将其包装为一个数组(结果是[System.Object[]]实例,其中$null作为唯一元素)。

    在PetSerAl的其他示例中,@()New-Object创建的数组和集合的行为可能令人惊讶-参见下文。
    @(...)的目的及其工作方式:

    宽松地说,@()用途array-subexpression operator 可以确保将表达式/命令的结果视为数组
    ,即使它恰好是标量(单个对象)。

    重要的: @()不构造数组。相反,它保证结果为一;因此, @( @( 1 ) )例如与 @( 1 ), 1相同。

    更准确地说, @()的行为如下:向PetSerAl表示感谢。
  • PSv5.1 + (Windows PowerShell 5.1和PowerShell [Core] 6+)中,使用这个表达式可以直接使用 , array constructor operator构造一个数组,从而优化@()@(1, 2):
  • 例如,1, 2@(, 1)相同,而, 1,相同。
  • 对于仅由System.Object[]构造的数组-这会产生@( ..., ..., ...)数组-此优化很有用,因为它节省了不必要的步骤:先展开该数组,然后重新打包(请参见下文)。
    据推测,此优化是由于使用@()构造数组的广泛且先前效率低下的做法所引起的,这是由于错误地认为需要[int[]]来构造数组而引起的。
  • 但是,在 Windows PowerShell v5.1中,仅优化在使用强制类型构建特定类型的数组时也意外地应用了优化,例如@([int[]] (1, 2)).GetType().Name(此行为已在 PowerShell [Core] 6+和更高版本中得到了纠正。较旧的Windows PowerShell版本不受影响();例如。,Int32[]产生@()。这是System.Object[]返回除@([int[]] (1, 2))[-1] = 'foo'之外的其他内容的唯一情况,并且假定它总是会导致意外错误和副作用;例如。:$a = [int[]] (1, 2); $b = @([int[]] $a)中断。@(...)意外地不会创建新数组-请参阅this GitHub issue
  • 否则:如果[System.Object[]]中的(第一个)语句是一个恰好是一个集合的表达式,则该集合被枚举;照原样收集命令的输出(通常是一对一的流);在这两种情况下,对象的最终计数决定了行为:
  • 如果结果为单个项目/不包含任何项目,则结果为,包装在类型为@('foo').GetType().Name 的单元素/空数组中。
  • 例如,Object[]产生@('foo').Count,而1产生'foo'.Count(尽管如上所述,在PSv3 +中,您可以直接使用@( & { } ).Count)。0产生[System.Management.Automation.Internal.AutomationNull]::Value(执行一个空脚本块将输出“空集合”
    (@())
  • 警告:围绕New-Object调用的 @(New-Object System.Collections.ArrayList).Count创建了一个数组/集合输出,该数组/集合输出包装在单元素外部数组中。
  • 1产生System.Object[]-空数组列表包装在单元素New-Object实例中。
  • 原因是@()由于是命令(例如cmdlet调用)而无法展开,因此@([system.collections.arraylist]::new()).Count仅看到单个项目(恰好是数组/集合),因此将其包装单项数组。
  • 可能令人困惑的是,当您使用表达式构造数组/集合时不会发生这种情况,因为表达式的输出是未包装的(展开的):
  • 0产生@();表达式输出一个空集合,该集合将展开为不包含任何项目的结果,并将System.Object[]重新打包为一个空(...)数组。
    请注意,在 PSv3 + 中,仅将额外的圆括号(New-Object)与New-Object一起使用-将@((New-Object System.Collections.ArrayList)).Count命令转换为表达式-会产生相同的结果:0也产生[System.Object[]]
  • 如果结果包含多个项目,则这些项目作为常规PowerShell数组($arr = @(Get-ChildItem *.txt))返回;例如。:
  • 使用命令:
  • Get-ChildItemSystem.Object[]数组
  • 中收集$arr = [int[]] (1, 2); @($arr)的一对一流输出
  • 使用表达式:
  • [int[]]枚举$arr数组System.Object[],然后将元素重新打包为System.Object[]数组。
  • 注意此过程的效率低下和类型保真度的潜在损失:原始数组被枚举并收集在始终为[array]类型的新数组中; 有效的替代方法是强制转换为[array] $result = ... (也可用于命令):ojit_code
  • 关于arrays - 没有 '.Count'属性的对象-使用@()(数组子表达式运算符)与[Array]类型转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45089739/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com