2009-07-04 7 views
7

¿Alguien puede explicar por qué esta secuencia de comandos arroja una excepción?La secuencia de comandos Powershell falla después de acceder a la propiedad Array.Length

$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) 

Básicamente, estoy creando una matriz de números, formateando la matriz y luego verificando su longitud y formateándola de nuevo.

El primer formato tiene éxito, pero el segundo formato arroja una excepción.

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) 
-------------------------------------------------------------------------------- 
+0

¿Debería ser esto en ServerFault? Tal vez no porque es un script, ¿pero no un script de administrador? –

+4

No debería, ya que esta es claramente una pregunta sobre el comportamiento extraño de un programa y no sobre administrar nada. – Joey

+0

+1. Esta es una pregunta fascinante (para mí), y para nada relacionada con el administrador. –

Respuesta

3

Eso es definitivamente extraño. Como solución alternativa se puede utilizar

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

que parece funcionar incluso después de acceder a los miembros de $byteArray.

Otra solución posible podría ser guardar la cadena formateada en una variable y volver a utilizarla.

En cuanto a por qué no funciona después de acceder a la propiedad Length no tengo ni idea.

+1

Gracias. Es el mismo trabajo que he estado usando. Parece que si copia la matriz a una nueva variable, puede usar esa variable para todas sus llamadas de formateo y no se lanzará ninguna excepción. – kervin

+0

De alguna manera, el acceso de miembro cambia algo en la matriz que desencadena este comportamiento con -f. Tal vez uno de los desarrolladores de Powershell sabe lo que está pasando. – Joey

1

Guau, eso es bastante fascinante. He jugado con esto durante unos minutos en PowerShell V2 y no puedo encontrar una razón sólida sobre por qué sucede esto.

Pero eso no me detendrá de especular :)

El problema es que el comando -f es esperar realmente una matriz de objetos. Lo que está sucediendo claramente en la línea del problema es que está interpretando $ byteArray como un elemento único frente a una matriz.

¿Pero por qué funciona la primera vez? Mi sospecha es que la matriz se evalúa perezosamente. Hasta que realmente llame a un método en el tipo de matriz, es simplemente un alias en la tubería. Por alguna casualidad, funciona en el primer caso porque solo está indexando en la línea de tubería existente o argumentos. Una vez que llamas a .Length, gela la tubería en un objeto y, por lo tanto, las llamadas posteriores lo interpretan correctamente como una matriz.

Una vez más, esto es solo una mera especulación. Te recomiendo encarecidamente que archives un error al conectar ya que huele a error.

4

Para añadir al rompecabezas:

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 

estoy de acuerdo con Jared que es una peculiaridad de la -f operador ver la variable como un objeto en lugar de una matriz, apoyado en parte por esto:

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 

Si el objeto subyacente no es aceptable como un parámetro, entonces debe haber algo especial acerca de cómo $a se almacena en un principio que hace -f feliz. Pero eso todavía no explica por qué llamar al GetLength() no afecta a $b en "forma de conjunto" en la forma en que Length (y Rank) parecen hacerlo.

Como han notado otros, el uso de @() parece funcionar de manera consistente.

Cuestiones relacionadas