Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Descripción breve
PowerShell tiene un sistema de tipos flexible que facilita el uso. Sin embargo, debe comprender cómo funciona para evitar resultados inesperados.
Descripción larga
Por defecto, las variables de PowerShell no tienen restricciones de tipo. Puede crear una variable que contenga una instancia de un tipo y, posteriormente, asignar valores de cualquier otro tipo. Además, PowerShell convierte automáticamente los valores en otros tipos, tanto explícita como implícitamente. Aunque la conversión implícita de tipos puede ser útil, hay problemas, especialmente para los usuarios más familiarizados con los lenguajes que tienen un control de tipos más estricto.
Variables restringidas de tipo y conversión de tipos explícita
Para restringir el tipo de una variable, coloque un literal de tipo a la izquierda del nombre de la variable en una asignación. Por ejemplo:
[int]$foo = 42
Puede utilizar la conversión de tipos para convertir explícitamente un valor a un tipo específico. Por ejemplo:
PS> $var = [int]'43'
PS> $var.GetType().Name
Int32
La restricción de tipos garantiza que solo se puedan asignar valores del tipo especificado a la variable. PowerShell realiza una conversión implícita si intenta asignar un valor de un tipo diferente que se puede convertir al tipo restringido. Para obtener más información, consulta la sección Conversión implícita de tipos de este artículo.
Conversión de tipos numéricos
Los tipos numéricos se pueden convertir en cualquier otro tipo numérico siempre que el tipo de destino sea capaz de contener el valor convertido. Por ejemplo:
PS> (42.1).GetType().Name
Double
PS> $byte = [byte] 42.1
PS> $byte
42
PS> $byte.GetType().Name
Byte
El valor 42.1 es un Double. Cuando se convierte en un Byte, PowerShell lo trunca en un entero 42, lo que es lo suficientemente pequeño como para caber en un Byte.
Al convertir números reales a tipos enteros, PowerShell usa el redondeo en lugar de truncar, específicamente mediante el método de redondeo al par más cercano.
En los ejemplos siguientes se muestra este comportamiento. Ambos valores se redondean al entero par más cercano, 22.
PS> [byte]21.5
22
PS> [byte]22.5
22
Para obtener más información, consulte la sección "Valores de punto medio y convenciones de redondeo" del método Math.Round.
Conversión de tipos booleanos
Un valor de cualquier tipo se puede convertir a un booleano.
En el caso de los tipos numéricos,
0convierte en$falsey cualquier otro valor se convierte en$true.PS> [boolean]0 False PS> [boolean]0.0 False PS> [boolean]-1 True PS> [boolean]1 True PS> [boolean]42.1 TruePara otros tipos, los valores NULL, las cadenas vacías y las matrices vacías se convierten en
$false.PS> [boolean]'' False PS> [boolean]@() False PS> [boolean]'Hello' TrueOtros valores, incluidas las tablas hash vacías, se convierten en
$true. Las colecciones de un solo elemento se evalúan al valor booleano de su único elemento. Las colecciones con más de 1 elemento son siempre$true.PS> [boolean]@(0) False PS> [boolean]@(0,0) True PS> [boolean]@{} True
Conversión de tipos de cadena
Un valor de cualquier tipo se puede convertir a una cadena. La conversión predeterminada consiste en llamar al método ToString() en el objeto .
Las matrices se convierten en cadenas. Cada elemento de la matriz se convierte en una cadena, individualmente y se combina con la cadena resultante. De forma predeterminada, los valores convertidos están separados por un espacio. El separador se puede cambiar estableciendo la variable de preferencia $OFS.
PS> [string] @(1, 2, 3)
1 2 3
Para obtener más información sobre $OFS, vea about_Preference_Variables.
Un valor de cadena único se puede convertir en una instancia de un tipo si el tipo implementa un método de Parse() estático. Por ejemplo, [bigint]'42' es igual que [bigint]::Parse('42', [cultureinfo]::InvariantCulture). El valor de [cultureinfo]::InvariantCulture opcional se enlaza a un parámetro de tipo IFormatProvider del método . Garantiza el comportamiento invariante de cultura de la conversión. No todas las implementaciones de Parse() métodos tienen este parámetro.
Nota
La conversión a y desde cadenas se realiza normalmente utilizando la cultura invariante. La cultura invariante se basa en, pero no es idéntica a, la cultura de US-English. En particular, utiliza por defecto el punto (.) como marca decimal y las fechas del primer mes al estilo estadounidense. Sin embargo, los cmdlets binarios realizan una conversión sensible a la cultura durante la vinculación de parámetros.
Conversión de tipos Enum
PowerShell puede convertir tipos Enum a y desde instancias Cadena. Por ejemplo, la cadena typecast [System.PlatformId]'Unix' es la misma que el valor enum [System.PlatformId]::Unix. PowerShell también controla las enumeraciones basadas en marcas correctamente para los valores separados por comas dentro de una cadena o como una matriz de cadenas. Tenga en cuenta los ejemplos siguientes:
[System.Reflection.TypeAttributes]'Public, Abstract'
[System.Reflection.TypeAttributes]('Public', 'Abstract')
Estos ejemplos son equivalentes a la expresión de enumeración:
[System.Reflection.TypeAttributes]::Public -bor
[System.Reflection.TypeAttributes]::Abstract
Otras conversiones de tipos
Un valor único (no matriz) se puede convertir en una instancia de un tipo si:
- Ese tipo tiene un constructor de parámetro único (público)
- Y el valor es del mismo tipo o puede ser coaccionado al tipo del parámetro
Por ejemplo, las dos líneas siguientes son equivalentes:
[regex]'a|b'
[regex]::new('a|b')`
Tipos implícitos
PowerShell también asigna tipos a valores literales automáticamente.
Los literales numéricos se escriben implícitamente de forma predeterminada. Los números se escriben en función de su tamaño. Por ejemplo, 42 es lo suficientemente pequeño como para almacenarse como un tipo de Int32 y 1.2 se almacena como un Double. Los enteros mayores que [int32]::MaxValue se almacenan como Int64. Mientras 42 que puede ser almacenado como un Byte y 1.2 puede ser almacenado como un tipo Single, la tipificación implícita utiliza Int32 y Double respectivamente. Para obtener más información, consulte about_Numeric_Literals.
Las cadenas literales se escriben implícitamente como string. Las instancias de Cadena de un solo carácter se pueden convertir desde y hacia el tipo Char. Sin embargo, PowerShell no tiene un tipo literal Char.
Conversión implícita de tipos
En determinados contextos, PowerShell puede convertir implícitamente valores a otros tipos. Estos contextos incluyen:
- Enlace de parámetros
- Variables restringidas por tipos
- Expresiones que usan operadores
- Contextos booleanos - PowerShell convierte las expresiones condicionales de
if,while,do, o sentenciasswitcha valores booleanos, como se ha descrito anteriormente. Para obtener más información, consulte about_Booleans. - Definiciones de tipos del Sistema de tipos extendidos (ETS): las conversiones de tipos se pueden definir de varias maneras:
- Uso del parámetro TypeConverter de Update-TypeData
- En archivos Types.ps1xml
- En código compilado para tipos decorados con un atributo TypeConverterAttribute
- Mediante clases derivadas de TypeConverter o PSTypeConverter
Conversiones de enlace de parámetros
PowerShell intenta convertir valores pasados a parámetros para que coincidan con el tipo de parámetro. La conversión de tipos de valores de parámetro se produce en cmdlets, funciones, scripts, bloques de scripts o métodos de .NET donde el parámetro se declara con un tipo específico. Declarar un parámetro con el tipo [Object] o no definir un tipo específico permite pasar cualquier tipo de valor a un parámetro. Los parámetros también pueden contar con conversiones personalizadas definidas al decorar los parámetros con el atributo ArgumentTransformationAttribute.
Para obtener más información, vea about_Parameter_Binding.
Procedimientos recomendados para el enlace de parámetros
Para los métodos .NET, es mejor pasar el tipo exacto esperado utilizando una conversión de tipo cuando sea necesario. Sin tipos exactos, PowerShell puede seleccionar la sobrecarga de método incorrecta. Además, las nuevas sobrecargas de método agregadas en versiones futuras de .NET pueden interrumpir el código existente. Para ver un ejemplo extremo de este problema, consulte esta pregunta Stack Overflow.
Si pasa una matriz a un parámetro con tipo [string], PowerShell podría convertir la matriz en una cadena como se ha descrito anteriormente. Tenga en cuenta la siguiente función básica:
function Test-String {
param([string] $String)
$String
}
Test-String -String 1, 2
Esta función genera 1 2 porque la matriz se convierte en una cadena. Para evitar este comportamiento, cree una función avanzada agregando el atributo [CmdletBinding()].
function Test-String {
[CmdletBinding()]
param([string] $String)
$String
}
Test-String -String 1, 2
En el caso de las funciones avanzadas, PowerShell se niega a enlazar la matriz a un tipo que no es de matriz. Al pasar una matriz, PowerShell devuelve el siguiente mensaje de error:
Test-String:
Line |
7 | Test-String -String 1, 2
| ~~~~
| Cannot process argument transformation on parameter 'String'. Cannot
| convert value to type System.String.
Desafortunadamente, no puede evitar este comportamiento para las llamadas a métodos de .NET.
PS> (Get-Date).ToString(@(1, 2))
1 2
PowerShell convierte la matriz en la cadena "1 2", que se pasa al parámetro Format del método ToString().
En el ejemplo siguiente se muestra otra instancia del problema de conversión de matriz.
PS> $bytes = [byte[]] @(1..16)
PS> $guid = New-Object System.Guid($bytes)
New-Object: Cannot find an overload for "Guid" and the argument count: "16".
PowerShell trata la matriz $bytes como una lista de parámetros individuales aunque $bytes sea una matriz de bytes y System.Guid tenga un constructor Guid(byte[]).
Este patrón de código común es una instancia de sintaxis de seudo-método, que no siempre funciona como se espera. Esta sintaxis se traduce en:
PS> [byte[]] $bytes = 1..16
PS> New-Object -TypeName System.Guid -ArgumentList $bytes
New-Object: Cannot find an overload for "Guid" and the argument count: "16".
Dado que el tipo de ArgumentList es [Object[]], un único argumento que resulta ser un array (de cualquier tipo) se vincula a él elemento a elemento. La solución consiste en encapsular $bytes en una matriz externa para que PowerShell busque un constructor con parámetros que coincidan con el contenido de la matriz externa.
PS> [byte[]] $bytes = 1..16
PS> $guid = New-Object -TypeName System.Guid -ArgumentList (, $bytes)
PS> $guid
Guid
----
04030201-0605-0807-090a-0b0c0d0e0f10
El primer elemento de la matriz encapsulada es nuestra instancia de [byte[]] original. Ese valor coincide con el constructor Guid(byte[]).
Una alternativa a la solución de envolver el array es utilizar el método estático intrínseco new().
PS> [byte[]] $bytes = 1..16
PS> [System.Guid]::new($bytes) # OK
Guid
----
04030201-0605-0807-090a-0b0c0d0e0f10
Conversiones de variables restringidas por tipos
Al asignar un valor a una variable restringida de tipo, PowerShell intenta convertir el valor al tipo de variable. Si el valor proporcionado se puede convertir al tipo de variable, la asignación se realiza correctamente.
Por ejemplo:
PS> [int]$foo = '43'
PS> $foo.GetType().Name
Int32
La conversión funciona porque la cadena '43' se puede convertir en un número.
Conversiones de operadores
PowerShell puede convertir implícitamente los operandos en una expresión para generar un resultado razonable. Además, algunos operadores tienen comportamientos específicos del tipo.
Operaciones numéricas
En operaciones numéricas, incluso si ambos operandos son del mismo tipo numérico, el resultado puede ser un tipo diferente, debido a la conversión automática de tipos para dar cabida al resultado.
PS> [int]$a = 1
PS> [int]$b = 2
PS> $result = $a / $b
PS> $result
0.5
PS> $result.GetType().Name
Double
Aunque ambos operandos son enteros, el resultado se convierte en un Double para admitir el resultado fraccionario. Para obtener una división entera, use los métodos estáticos [int]::Truncate() o [Math]::DivRem(). Para obtener más información, vea truncate() y DivRem().
En la aritmética de enteros, cuando el resultado desborda el tamaño de los operandos, PowerShell usa de forma predeterminada Double para los resultados, incluso cuando el resultado podría caber en un tipo de Int64.
PS> $result = [int]::MaxValue + 1
PS> $result
2147483648
PS> $result.GetType().Name
Double
Si desea que el resultado sea un Int64, puede moldear el tipo de resultado o los operandos.
PS> ([int64]([int]::MaxValue + 1)).GetType().Name
Int64
Sin embargo, use cuidado al convertir los resultados en un tipo específico. Por ejemplo, convertir el resultado al tipo [decimal] puede provocar la pérdida de precisión.
Agregar 1 al valor máximo de Int64 da como resultado un tipo Double. Al convertir un tipo Double a un tipo Decimal, el resultado es 9223372036854780000, que no es preciso.
PS> ([int64]::MaxValue + 1).GetType().Name
Double
PS> [decimal]([int64]::MaxValue + 1)
9223372036854780000
La conversión se limita a 15 dígitos de precisión. Para obtener más información, consulte la sección de Observaciones de la documentación del constructor Decimal(Double).
Para evitar una pérdida de precisión, use el sufijo D en el literal 1. Al agregar el sufijo D, PowerShell convierte el [int64]::MaxValue en un decimal antes de agregar 1D.
PS> ([int64]::MaxValue + 1D).GetType().Name
Decimal
PS> ([int64]::MaxValue + 1D)
9223372036854775808
Para obtener más información sobre los sufijos numéricos, vea about_Numeric_Literals.
Normalmente, el operando del lado izquierdo (LHS) de los operadores PowerShell determina el tipo de datos utilizado en la operación. PowerShell convierte (coacciona) el operando del lado derecho (RHS) al tipo requerido.
PS> 10 - ' 9 '
1
En este ejemplo, el operando RHS es la cadena ' 9 ', que se convierte implícitamente en un entero antes de la operación de resta. Lo mismo sucede con los operadores de comparación.
PS> 10 -eq ' 10'
True
PS> 10 -eq '0xa'
True
Hay excepciones al usar operadores aritméticos (+, -, *, /) con operandos no numéricos .
Cuando se usan los operandos - y / con cadenas, PowerShell convierte ambos operandos de cadenas a números.
PS> '10' - '2'
8
PS> '10' / '2'
5
Por el contrario, los operadores + y * tienen semántica específica de cadenas (concatenación y replicación).
PS> '10' + '2'
102
PS> '10' * '2'
1010
Al usar valores de booleanos con operadores aritméticos, PowerShell convierte los valores en enteros: $true se convierte en [int]1 y $false se convierte en [int]0.
PS> $false - $true
-1
La única excepción es la multiplicación (*) de dos booleanos.
PS> $false * $true
InvalidOperation: The operation '[System.Boolean] * [System.Boolean]' is not
defined.
Para otros tipos de LHS, los operadores aritméticos solo tienen éxito si un tipo dado define de forma personalizada estos operadores a través de la sobrecarga de operadores.
Operaciones de comparación
Los operadores de comparación, como -eq, -lty -gt, pueden comparar operandos de diferentes tipos. El comportamiento de los tipos que no son cadenas y no primitivos depende de si el tipo LHS implementa interfaces como IEquatable y IComparable.
Los operadores de comparación basados en colecciones (-in y -contains) realizan comparaciones por elemento -eq hasta que se encuentra una coincidencia. Es cada elemento individual de la colección operando que impulsa cualquier tipo de coerción.
PS> $true -in 'true', 'false'
True
PS> 'true', 'false' -contains $true
True
Ambos ejemplos devuelven un resultado verdadero porque 'true' -eq $true produce $true.
Para obtener más información, vea sobre_operadores_de_comparación.