【问题标题】:Confused Powershell returned array type困惑的 Powershell 返回的数组类型
【发布时间】:2015-08-04 21:57:46
【问题描述】:

以下显示返回类型不同取决于返回的行数。为什么要这样设计?很容易假设它总是返回一个数组并编写代码$a.Length$a | % { ....},当它只返回一行时会引发错误,除非它写为$a = @(invoke-....),即容易忘记。

$a=Invoke-Sqlcmd -ServerInstance server "select 1 a"
$b=Invoke-Sqlcmd -ServerInstance server "select 1 a union all select 2"
$a.GetType()
IsPublic IsSerial 名称 BaseType -------- -------- ---- -------- True False DataRow System.Object

以下语句返回一个对象数组(顺便说一句,为什么不是 DataRow 数组?)

$b.GetType()
IsPublic IsSerial 名称 BaseType -------- -------- ---- -------- 真真对象[] System.Array

但是,gm 为两个变量返回相同的类型。为什么会这样设计,这可能会让人很困惑。

问题:

  1. 只返回一项时,删除数组有什么意义?
  2. 为什么gm 获取数组的项类型?如何gm的数组?
  3. 为什么getType()在返回数组类型的时候不能返回item的数据类型?

?

PS SQLSERVER:\> $a|gm


   TypeName: System.Data.DataRow

Name              MemberType            Definition
----              ----------            ----------
AcceptChanges     Method                void AcceptChanges()
......
ToString          Method                string ToString()
Item              ParameterizedProperty System.Object Item(int columnIndex) {get;set;}, System.Object Item(string co...
a                 Property              int a {get;set;}


PS SQLSERVER:\> $b|gm


   TypeName: System.Data.DataRow

Name              MemberType            Definition
----              ----------            ----------
AcceptChanges     Method                void AcceptChanges()
......
ToString          Method                string ToString()
Item              ParameterizedProperty System.Object Item(int columnIndex) {get;set;}, System.Object Item(string co...
a                 Property              int a {get;set;}

【问题讨论】:

  • 我希望我能回答这个问题,但我想我错过了一些关键的部分。 1. 这可能高达 Invoke-Sqlcmd 并且还取决于您的 PowerShell 版本。 2. Get-Member 作用于管道中传递的元素而不是整个对象,这就是为什么 3. 返回它所做的事情。
  • 你用的是什么版本的powershell?

标签: powershell


【解决方案1】:
  1. 大多数时候,在 PowerShell 中,返回对象的函数/cmdlet 只是简单地返回对象。如果要返回超过 1 个对象,则该函数会一直返回对象,直到完成。 PowerShell 处理所有返回的对象并为您提供一个数组。
  2. gmGet-Member 的别名。当您通过管道$a | gm 调用它时,您将其作为管道调用。在这种情况下,$a 中的每个对象单独传递给Get-Member,因此它返回单个对象的类型。如果它们都相同,那么它只会显示一次,但实际上是在检查所有这些。您可以通过调用 Get-Member -InputObject $a 来防止这种情况发生,如果它是一个数组,它应该会向您显示数组类型。
  3. 与上面类似,.GetType() 获取调用它的任何对象的类型,所以如果它是一个数组,那么它会返回它;它不是在看单个元素。

我还想指出,% (ForEach-Object) 和 foreach() 在不用于数组时可以正常工作:"hello" | % { $_ }foreach($msg in "hello") { $msg } 也是如此。

解决$a.Length在返回值为单个对象时不起作用的问题,这取决于您的powershell版本。

在版本 2 中,您将看到您所看到的行为:您必须先将其包装在一个数组中,或者使用类似以下内容的数组来测试:

if ($a -is [Array]) {
    $itemCount = $a.Length
} else {
    $itemCount = 1
}

但是,在 powershell 3+ 中,即使 $a 只是某个对象而不是数组,您也可以执行 $a.Length。它将返回 1。长度可能不会显示在自动完成或智能感知中,但它会起作用。

【讨论】:

  • 对于$a | % { ... },我的意思是$a.Length。我已经更新了问题。
  • @dc7a9163d9 什么版本的powershell?
  • @Briantist:更正你关于 PS 3+ 的最后一行:$a.Length 将起作用除非你使用严格模式,你应该这样做:-) 查看我最近的@ 987654321@,问题 2。
  • 没错,我也是严格模式的粉丝(模块内部除外),我已经在其他答案中写过它。但至少在 3+ 中,PowerShell 有能力按书面方式处理它,您可以选择不使用严格模式(大多数情况下),但在 v2 中您没有这种选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 2015-04-02
相关资源
最近更新 更多