Sdílet prostřednictvím


o_převodu_typů

Krátký popis

PowerShell má flexibilní systém typů, který usnadňuje použití. Musíte ale pochopit, jak funguje, abyste se vyhnuli neočekávaným výsledkům.

Dlouhý popis

Ve výchozím nastavení nejsouproměnné PowerShellu. Můžete vytvořit proměnnou obsahující instanci jednoho typu a později přiřadit hodnoty jakéhokoli jiného typu. PowerShell také automaticky převede hodnoty na jiné typy, a to explicitně i implicitně. I když může být převod implicitního typu užitečný, existují nástrahy, zejména pro uživatele, kteří znají jazyky, které mají přísnější zpracování typů.

Proměnné s omezeným typem a explicitní převod typů

Chcete-li omezit typ proměnné, umístěte literál typu nalevo od názvu proměnné při přiřazování. Například:

[int]$foo = 42

Přetypování typů můžete použít k explicitní převodu hodnoty na konkrétní typ. Například:

PS> $var = [int]'43'
PS> $var.GetType().Name
Int32

Omezení typu zajišťuje, že proměnné mohou být přiřazeny pouze hodnoty zadaného typu. PowerShell provede implicitní převod, pokud se pokusíte přiřadit hodnotu jiného typu, který lze převést na omezený typ. Další informace najdete v části tohoto článku Implicitní převod typu.

Převod číselného typu

Číselné typy lze převést na jakýkoli jiný číselný typ, pokud cílový typ dokáže převést převedenou hodnotu. Například:

PS> (42.1).GetType().Name
Double
PS> $byte = [byte] 42.1
PS> $byte
42
PS> $byte.GetType().Name
Byte

Hodnota 42.1 je Double. Když ho přetypujete na Bajt, PowerShell ho zkrátí na celé číslo 42, které je dostatečně malé, aby se vešly do Bajtu.

Při převodu reálných čísel na celočíselné typy používá PowerShell místo zkrácení zaokrouhlení, konkrétně metodou zaokrouhlování na nejbližší sudé. Toto chování ilustrují následující příklady. Obě hodnoty se zaokrouhlují na nejbližší sudé číslo 22.

PS> [byte]21.5
22
PS> [byte]22.5
22

Další informace najdete v části hodnoty středního bodu a konvence zaokrouhlování metody Math.Round.

Převod booleovského typu

Hodnota , libovolného typu, lze přetypovat na Boolean.

  • U číselných typů 0 převede na $false a všechny ostatní hodnoty se převedou na $true.

    PS> [boolean]0
    False
    PS> [boolean]0.0
    False
    PS> [boolean]-1
    True
    PS> [boolean]1
    True
    PS> [boolean]42.1
    True
    
  • Pro jiné typy jsou nullové hodnoty, prázdné řetězce a prázdná pole převedeny na $false.

    PS> [boolean]''
    False
    PS> [boolean]@()
    False
    PS> [boolean]'Hello'
    True
    

    Jiné hodnoty, včetně prázdných hashovacích tabulek, se převedou na $true. Kolekce s jedním prvkem se vyhodnocují jako logická hodnota jejich jednoho a jediného prvku. Kolekce s více než 1 prvkem jsou vždy $true.

    PS> [boolean]@(0)
    False
    PS> [boolean]@(0,0)
    True
    PS> [boolean]@{}
    True
    

Převod typu řetězce

Hodnotu libovolného typu lze převést na řetězec. Výchozí převod je zavolání metody ToString() na objektu.

Pole se převádějí na řetězce. Každý prvek v poli se převede na řetězec, jednotlivě a spojí se s výsledným řetězcem. Ve výchozím nastavení jsou převedené hodnoty oddělené mezerou. Oddělovač lze změnit nastavením proměnné předvoleb $OFS.

PS> [string] @(1, 2, 3)
1 2 3

Další informace o $OFSnaleznete v tématu about_Preference_Variables.

Jednu řetězcovou hodnotu lze převést na instanci typu, pokud typ implementuje statickou Parse() metodu. Například [bigint]'42' je stejná jako [bigint]::Parse('42', [cultureinfo]::InvariantCulture). Volitelná [cultureinfo]::InvariantCulture hodnota se sváže s parametrem typu IFormatProvider metody. Zajišťuje chování převodu nezávislé na kultuře. Ne všechny implementace Parse() metod mají tento parametr.

Poznámka

Obvykle se převod na řetězce a z řetězců provádí pomocí invariantní jazykové verze. Invariantní kulturní verze je založena na kultuře US-English, ale není s ní shodná. Ve výchozím nastavení používá tečku (.) jako desetinnou čárku a první kalendářní data ve stylu USA. Binární cmdlety provádějí konverzi závislou na jazyku během vazby parametrů.

Převod typu výčtu

PowerShell může převést typy výčtu z instancí řetězců a z těchto typů. Například řetězec typecast [System.PlatformId]'Unix' je stejný jako hodnota výčtu [System.PlatformId]::Unix. PowerShell také správně zpracovává výčty založené na příznakech pro hodnoty oddělené čárkami uvnitř řetězce nebo jako pole řetězců. Podívejte se na následující příklady:

[System.Reflection.TypeAttributes]'Public, Abstract'
[System.Reflection.TypeAttributes]('Public', 'Abstract')

Tyto příklady jsou ekvivalentní výrazu pro enum.

[System.Reflection.TypeAttributes]::Public -bor
    [System.Reflection.TypeAttributes]::Abstract

Převody jiných typů

Jedinou hodnotu (nikoli pole) lze převést na instanci typu, pokud:

  • Tento typ má (veřejný) konstruktor s jedním parametrem.
  • A hodnota je stejná typem nebo může být převedena na typ parametru.

Například následující dva řádky jsou ekvivalentní:

[regex]'a|b'
[regex]::new('a|b')`

Implicitní typy

PowerShell také automaticky přiřazuje typy literálovým hodnotám.

Číselné literály jsou ve výchozím nastavení implicitně zadané. Čísla se zadají na základě jejich velikosti. Například 42 je dostatečně malá, aby byla uložena jako typ Int32 a 1.2 je uložena jako Double. Celá čísla větší než [int32]::MaxValue jsou uložena jako Int64 . lze uložit jako bajt a lze uložit jako typ Single, implicitní psaní používá Int32 a Double. Další informace najdete v tématu about_Numeric_Literals.

Literální řetězce jsou implicitně zadány jako Řetězcové. Jednoznakové Řetězce instance lze převést na a z typu Char. PowerShell ale nemá žádný typ literálu char.

Implicitní převod typů

V určitých kontextech může PowerShell implicitně převést hodnoty na jiné typy. Mezi tyto kontexty patří:

  • Vazba parametru
  • Proměnné s omezením typu
  • Výrazy používající operátory
  • Logické kontexty – PowerShell převede podmíněné výrazy if, while, donebo switch na logické hodnoty, jak jsme popsali dříve. Další informace naleznete v tématu about_Booleans.
  • Definice typů rozšířeného systému typů (ETS) – Převody typů lze definovat několika způsoby:

Převody vazeb parametrů

PowerShell se pokusí převést hodnoty předané parametrům tak, aby odpovídaly typu parametru. K převodu hodnot parametrů dochází v cmdletech, funkcích, skriptech nebo metodách .NET, kde je parametr deklarován určitým typem. Deklarování parametru s typem [Object] nebo nedefinováním konkrétního typu umožňuje předání libovolného typu hodnoty do parametru. Parametry mohou mít také vlastní převody definované označením parametrů pomocí atributu ArgumentTransformationAttribute.

Další informace najdete v tématu about_Parameter_Binding.

Osvědčené postupy pro vazbu parametrů

Pro metody .NET je lepší předat přesný typ očekávaný pomocí přetypování typu tam, kde je to potřeba. Bez konkrétních typů může PowerShell vybrat nesprávné přetížení metody. Nové přetížení metody přidané v budoucích verzích rozhraní .NET také může narušit existující kód. Pro extrémní příklad tohoto problému se podívejte na tuto otázku Stack Overflow.

Pokud předáte pole parametru datového typu [string], PowerShell může pole převést na řetězec, jak jsme popsali dříve. Vezměte v úvahu následující základní funkci:

function Test-String {
    param([string] $String)
    $String
}

Test-String -String 1, 2

Tato funkce vypíše 1 2, protože pole je převedeno na řetězec. Pokud se chcete tomuto chování vyhnout, vytvořte pokročilou funkci přidáním atributu [CmdletBinding()].

function Test-String {
    [CmdletBinding()]
    param([string] $String)
    $String
}

Test-String -String 1, 2

V případě pokročilých funkcí PowerShell odmítne svázat pole s jiným typem než pole. Když předáte pole, PowerShell vrátí následující chybovou zprávu:

Test-String:
Line |
   7 |  Test-String -String 1, 2
     |                      ~~~~
     | Cannot process argument transformation on parameter 'String'. Cannot
     | convert value to type System.String.

Toto chování se bohužel nedá vyhnout voláním metody .NET.

PS> (Get-Date).ToString(@(1, 2))
1 2

PowerShell převede pole na řetězec "1 2", který se předá Format parametru ToString() metody.

Následující příklad ukazuje další příklad problému s převodem pole.

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 považuje pole $bytes za seznam jednotlivých parametrů, i když $bytes je pole bajtů a System.Guid má konstruktor Guid(byte[]).

Tento běžný vzor kódu je příkladem syntaxe pseudo metody, která nefunguje vždy podle očekávání. Tato syntaxe se překládá na:

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".

Vzhledem k tomu, že typ ArgumentList je [Object[]], jeden argument, který se stane polem (libovolného typu) váže na něj prvek podle elementu. Alternativním řešením je zabalit $bytes do vnějšího pole, aby PowerShell hledal konstruktor s parametry, které odpovídají obsahu vnějšího pole.

PS> [byte[]] $bytes = 1..16
PS> $guid = New-Object -TypeName System.Guid -ArgumentList (, $bytes)
PS> $guid

Guid
----
04030201-0605-0807-090a-0b0c0d0e0f10

První položkou zabaleného pole je naše původní instance objektu [byte[]]. Tato hodnota odpovídá konstruktoru Guid(byte[]).

Alternativou k alternativnímu řešení pro zabalení pole je použití vnitřní statické new() metody.

PS> [byte[]] $bytes = 1..16
PS> [System.Guid]::new($bytes)  # OK

Guid
----
04030201-0605-0807-090a-0b0c0d0e0f10

Převody proměnných s omezením typu

Když přiřadíte hodnotu proměnné s omezením typu, PowerShell se pokusí převést hodnotu na typ proměnné. Pokud zadaná hodnota může být převedena na typ proměnné, přiřazení bude úspěšné.

Například:

PS> [int]$foo = '43'
PS> $foo.GetType().Name
Int32

Převod funguje, protože řetězec '43' lze převést na číslo.

Převody operátorů

PowerShell může implicitně převést operandy ve výrazu tak, aby vznikl rozumný výsledek. Některé operátory mají také chování specifické pro typ.

Číselné operace

Při numerických operacích může být výsledek jiného typu, i když oba operandy mají stejný číselný typ, kvůli automatickému převodu typu, který se přizpůsobí výsledku.

PS> [int]$a = 1
PS> [int]$b = 2
PS> $result = $a / $b
PS> $result
0.5
PS> $result.GetType().Name
Double

I když jsou oba operandy celá čísla, výsledek se převede na Double, aby podporoval desetinný výsledek. Pokud chcete získat skutečné celočíselné dělení, použijte [int]::Truncate() nebo [Math]::DivRem() statické metody. Další informace najdete v tématu truncate() a DivRem().

V celočíselné aritmetice platí, že když výsledek překročí velikost operandů, PowerShell použije pro výsledky výchozí typ Double, a to i tehdy, když by se výsledek vešel do typu Int64.

PS> $result = [int]::MaxValue + 1
PS> $result
2147483648
PS> $result.GetType().Name
Double

Pokud chcete, aby výsledek byl Int64, můžete přetypovat typ výsledku nebo operandy.

PS> ([int64]([int]::MaxValue + 1)).GetType().Name
Int64

Při přetypování výsledků na určitý typ však buďte opatrní. Například přetypování výsledku na typ [decimal] může vést ke ztrátě přesnosti. Když přidáte 1 k maximální hodnotě Int64, výsledkem bude typ Double. Při přetypování Double na typ Decimal je výsledek 9223372036854780000, což není přesný.

PS> ([int64]::MaxValue + 1).GetType().Name
Double
PS> [decimal]([int64]::MaxValue + 1)
9223372036854780000

Převod je omezen na 15 číslic přesnosti. Další informace naleznete v Poznámky části Decimal(Double) dokumentace konstruktoru.

Pokud se chcete vyhnout ztrátě přesnosti, použijte příponu D v literálu 1. Když přidáte příponu D, PowerShell převede [int64]::MaxValue na Desetinné číslo před přidáním 1D.

PS> ([int64]::MaxValue + 1D).GetType().Name
Decimal
PS> ([int64]::MaxValue + 1D)
9223372036854775808

Další informace o číselných příponách najdete v tématu about_Numeric_Literals.

Operand (LHS) na levé straně operátorů PowerShell obvykle určuje datový typ použitý v operaci. PowerShell převede (donutí) operand na pravé straně (RHS) na požadovaný typ.

PS> 10 - ' 9 '
1

V tomto příkladu je operand RHS řetězcový ' 9 ', který je implicitně převeden na celé číslo před operací odčítání. Totéž platí pro relační operátory.

PS> 10 -eq ' 10'
True
PS> 10 -eq '0xa'
True

Při použití operátorů arithmetic_ (+, -, *, /) s nečíselnými operandy existují výjimky.

Když použijete - a / operandy s řetězci, PowerShell převede oba operandy z řetězců na čísla.

PS> '10' - '2'
8
PS> '10' / '2'
5

Naproti tomu operátory + a * mají sémantiku specifickou pro řetězec (zřetězení a replikaci).

PS> '10' + '2'
102
PS> '10' * '2'
1010

Když použijete logické hodnoty s aritmetickými operátory, PowerShell převede hodnoty na celá čísla: $true se stane [int]1 a $false se stane [int]0.

PS> $false - $true
-1

Jednou výjimkou je násobení (*) dvou logických hodnot.

PS> $false * $true
InvalidOperation: The operation '[System.Boolean] * [System.Boolean]' is not
defined.

U jiných typů LHS jsou aritmetické operátory úspěšné pouze v případě, že daný typ přizpůsobí si tyto operátory přetížením operátorů.

Operace porovnání

Relační operátory, například -eq, -lta -gt, mohou porovnávat operandy různých typů. Chování neřetězců a jiných než primitivních typů závisí na tom, zda typ LHS implementuje rozhraní, jako jsou IEquatable a IComparable.

Operátory pro porovnání založené na kolekci (-in a -contains) provádějí porovnání jednotlivých prvků -eq, dokud se nenalezne shoda. Každý jednotlivý prvek operandu kolekce, který vyvolává jakoukoli typovou konverzi.

PS> $true -in 'true', 'false'
True
PS> 'true', 'false' -contains $true
True

Oba příklady vracejí hodnotu true, protože 'true' -eq $true vrací $true.

Další informace naleznete v tématu about_Comparison_Operators.