访问Array.Length属性后,Powershell脚本失败

时间:2009-07-04 00:40:58

标签: powershell

有人可以解释为什么这个脚本会抛出异常吗?

$byteArray = @(1,2,3)
write-Output ( "{0:X}{1:X}{2:X}" -f $byteArray )
write-Output ( $byteArray.Length -ge 3 )
write-Output ( "{0:X}{1:X}{2:X}" -f $byteArray )

基本上,我正在创建一个数字数组,格式化数组,然后检查它的长度并再次格式化。

第一种格式成功,但第二种格式抛出异常。

123
True
--------------------------------------------------------------------------------
POWERSHELL EXCEPTION 
EXCEPTION TYPE:System.Management.Automation.RuntimeException
MESSAGE:Error formatting a string: Index (zero based) must be greater than or equal to zero and less than the size of the argument list..
POSITION:
At line:4 char:36
+ write-Output ( "{0:X}{1:X}{2:X}" -f  <<<< $byteArray )
--------------------------------------------------------------------------------

3 个答案:

答案 0 :(得分:4)

添加到拼图:

PS > $a = @(1,2,3)
PS > $b = $a
PS > [object]::ReferenceEquals($a, $b)
True
PS > $a.Length
3
PS > [object]::ReferenceEquals($a, $b)
True
PS > "{0:X}{1:X}{2:X}" -f $a
Error formatting a string: Index (zero based) must be greater than or equal to zero and less than the size of the argum
ent list..
At line:1 char:21
+ "{0:X}{1:X}{2:X}" -f  <<<< $a
PS > "{0:X}{1:X}{2:X}" -f $b
123
PS > $b.GetLength(0)
3
PS > "{0:X}{1:X}{2:X}" -f $b
123
PS > [object]::ReferenceEquals($a, $b)
True

我倾向于同意Jared的观点,-f运算符将变量视为对象而不是数组,这部分得到了支持:

PS > $a = @(1,2,3)
PS > "{0:X}{1:X}{2:X}" -f $a
123
PS > "{0:X}{1:X}{2:X}" -f $a.PSObject
Error formatting a string: Index (zero based) must be greater than or equal to zero and less than the size of the argum
ent list..
At line:1 char:21

如果基础对象不能作为参数接受,那么最初存储$a的方式必须有一些特别之处,以使-f满意。但这仍然无法解释为什么调用GetLength()不会像$b(和Length)那样影响Rank的“数组”。

正如其他人所指出的那样,使用@()确实可以保持一致。

答案 1 :(得分:3)

这绝对是奇怪的。作为解决方法,您可以使用

"{0:X}{1:X}{2:X}" -f @($byteArray)

即使在访问$byteArray的成员之后似乎也能正常工作。

另一种可能的解决方法可能是将格式化的字符串保存到变量并重新使用它。

至于为什么在访问Length属性后它不起作用我不知道。

答案 2 :(得分:1)

哇,这真是令人着迷。我已经在PowerShell V2上玩了几分钟,我找不到一个关于为什么会发生这种情况的快速原因。

但这不会阻止我猜测:)

问题是-f命令确实需要一个对象数组。在问题中明确发生的是它将$ byteArray解释为单个元素而不是数组。

但为什么它第一次起作用?我的怀疑是数组是惰性评估的。直到您实际调用数组类型的方法,它只是管道的别名。通过一些侥幸它在第一种情况下工作,因为它只是索引到现有的管道或参数。一旦调用.Length,它就会将管道凝固成一个对象,因此稍后调用会将其正确地解释为数组。

同样,这主要是猜测。我强烈建议你在连接上提交一个bug,因为它闻起来像一个bug。