Welcome to Our Website

Vše, co jste chtěli vědět o výjimky

  • 05/23/2020
  • 14 minut číst
    • j
    • f

zpracování Chyb je jen součástí života, když dojde na psaní kódu. Často můžeme zkontrolovat a ověřitpodmínky pro očekávané chování. Když dojde k neočekávanému, obrátíme se na manipulaci s výjimkami., Youcan snadno zvládnout výjimky generované kódem jiných lidí, nebo si můžete vytvořit své vlastníexceptions pro ostatní zvládnout.

Poznámka:

původní verze tohoto článku vyšla na blogu napsal @KevinMarquette. Tým ThePowerShell děkuje Kevinovi za sdílení tohoto obsahu s námi. Podívejte se prosím na jeho blog atPowerShellExplained.com.

základní terminologie

musíme pokrýt některé základní pojmy, než skočíme do tohoto.

výjimka

výjimka je jako událost, která je vytvořena, když normální zpracování chyb nemůže problém vyřešit.,Pokus o rozdělení čísla nulou nebo vyčerpání paměti jsou příklady něčeho, co vytváří anexcepci. Někdy autor kódu, který používáte, vytváří výjimky pro určité problémykdyž k nim dojde.

házet a chytit

když dojde k výjimce, říkáme, že je vyvolána výjimka. Chcete-li zvládnout hozenou výjimku, vyje třeba ji chytit. Pokud je výjimka hozena a není něčím chycena, skript se zastaví.

zásobník hovorů

zásobník hovorů je seznam funkcí, které se navzájem volaly., Když je funkce volána, je tozdostane se přidán do zásobníku nebo do horní části seznamu. Když funkce ukončí nebo vrátí, je odstraněnaz zásobníku.

je-li vyvolána výjimka, je tento zásobník volání zkontrolován, aby mohl Správce výjimek chytit.

chyby ukončení a ukončení

výjimka je obecně chyba ukončení. Hozená výjimka je buď chycena, nebo topřekončí aktuální provedení. Ve výchozím nastavení je ukončující chyba generována Write-Errora přidává chybu do výstupního proudu bez vyhazování výjimky.,

tento bod, protože Write-Error a jiné non-ukončení chyby nejsou spoušťcatch.

polykání výjimky

to je, když chytíte chybu jen proto, abyste ji potlačili. Udělejte to opatrně, protože to může udělattroupleshooting problémy velmi obtížné.

syntaxe základního příkazu

zde je rychlý přehled Základní syntaxe zpracování výjimek používané v PowerShellu.

hodit

Chcete-li vytvořit vlastní událost výjimky, hodíme výjimku sthrow Klíčové slovo.,

function Start-Something{ throw "Bad thing happened"}

tím se vytvoří runtime výjimka, která je ukončující chyba. Je zpracováncatch ve funkci acalling nebo ukončí skript se zprávou, jako je tato.

Write-Error-Erroraction Stop

zmínil jsem se, že Write-Error ve výchozím nastavení nevyhodí chybu ukončení. Pokud zadáte-ErrorAction Stop Write-Errorgeneruje ukončení chyby, které mohou být řešeny pomocícatch.,

Write-Error -Message "Houston, we have a problem." -ErrorAction Stop

Děkuji Lee Dailey za připomenutí použití -ErrorAction Stop tímto způsobem.

Cmdlet -ErrorAction

Pokud zadáte -ErrorAction Stop na nějaké pokročilé funkce nebo rutiny, to se změní vše Write-Errorprohlášení do ukončení chyby, které se zastavení exekuce nebo které mohou být řešeny pomocí catch.,

Start-Something -ErrorAction Stop

Try/Catch

způsob zpracování výjimek funguje v PowerShell (a mnoho jiných jazyků) je, že první try asection kódu a pokud to vyhodí chybu, můžete catch. Zde je rychlý vzorek.

catch skript běží pouze v případě, že dojde k chybě ukončení. Pokud se try provede správně, přeskočí catch.,

zkuste / konečně

někdy nemusíte zpracovávat chybu, ale stále potřebujete nějaký kód k provedení, pokud se exceptionhappens nebo ne. finally skript dělá přesně to.

podívejte se na tento příklad:

kdykoli otevřete nebo se připojíte ke zdroji, měli byste jej zavřít. PokudExecuteNonQuery() hodí výjimku, připojení není uzavřeno. Zde je stejný kód uvnitř blokutry/finally.

v tomto příkladu je připojení uzavřeno, pokud dojde k chybě. Je také uzavřen, pokud neexistuje žádná chyba., finally skript běží pokaždé.

protože výjimku nezachytíte, stále se šíří do zásobníku hovorů.

Try/Catch/Konečně

je naprosto platný pomocí catch finally dohromady. Většinu času budete používat jeden nebodruhý, ale můžete najít scénáře, kde používáte oba.

$ PSItem

nyní, když jsme dostali základy z cesty, můžeme kopat trochu hlouběji.,

Uvnitř catch blok, tam je automatické proměnné ($PSItem nebo $_) typ ErrorRecord, který obsahuje podrobnosti o výjimce. Zde je rychlý přehled některých klávesnicvlastnosti.

pro tyto příklady jsem použil neplatnou cestu v ReadAllText pro generování této výjimky.

::ReadAllText( '\\test\no\filefound.log')

PSItem.ToString ()

to vám dává nejčistší zprávu, kterou chcete použít při protokolování a obecném výstupu., ToString() isautomatically volal, jestli $PSItem je umístěn uvnitř řetězce.

catch{ Write-Output "Ran into an issue: $($PSItem.ToString())"}catch{ Write-Output "Ran into an issue: $PSItem"}

$PSItem.InvocationInfo

tato vlastnost obsahuje další informace shromážděné PowerShell o funkci nebo scriptwhere výjimka byla hozena. Zde je InvocationInfo ze vzorové výjimky, kterou Icreated.

důležité informace zde ScriptName Line kód ScriptLineNumber, kde je aplikace spuštěna.

$PSItem.,ScriptStackTrace

Tato vlastnost ukazuje pořadí volání funkcí, které musíš kódu, kde výjimkou wasgenerated.

volám pouze na funkce ve stejném skriptu, ale to by sledovalo hovory, pokud by se jednalo o multiplescripts.

$PSItem.Výjimka

toto je skutečná výjimka, která byla hozena.

$PSItem.Výjimek.Zpráva

toto je obecná zpráva, která popisuje výjimku a je dobrým výchozím bodem, kdyžpřestřelování. Většina výjimek má výchozí zprávu, ale může být také nastavena na něco, co je vlastní, kdyvyloučení výjimky.,

PS> $PSItem.Exception.MessageException calling "ReadAllText" with "1" argument(s): "The network path was not found."

toto je také zpráva vrácená při volání $PSItem.ToString() pokud naErrorRecord.

$PSItem.Výjimek.Innerexception

výjimky mohou obsahovat vnitřní výjimky. To je často případ, kdy kód, který volátecatches výjimku a hodí jinou výjimku. Původní výjimka je umístěna uvnitřnová výjimka.

PS> $PSItem.Exception.InnerExceptionMessageThe network path was not found.

vrátím se k tomu později, když mluvím o opakovaných výjimkách.

$PSItem.Výjimek.,StackTrace

toto jeStackTrace pro výjimku. Ukázal jsem ScriptStackTrace výše, ale tohle je forthe volání do spravovaného kódu.

at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize, Boolean checkHost)at System.IO.File.InternalReadAllText(String path, Encoding encoding, Boolean checkHost)at CallSite.Target(Closure , CallSite , Type , String )

tuto stopu získáte pouze tehdy, když je událost vyvolána ze spravovaného kódu. Volám a .NETframework funguje přímo tak, že je vše, co můžeme vidět v tomto příkladu. Obecně, když se díváte na stopu zásobníku, hledáte místo, kde se váš kód zastaví a začnou systémové hovory.

práce s výjimkami

existuje více výjimek než základní vlastnosti syntaxe a výjimky.,

chytání zadaných výjimek

můžete být selektivní s výjimkami, které chytíte. Výjimky mají typ a můžete specifikovattyp výjimky, kterou chcete chytit.

typ výjimky je kontrolována pro každou catch blokovat, dokud jeden je zjištěno, že odpovídá vašemu výjimkou.Je důležité si uvědomit, že výjimky mohou dědit od jiných výjimek. Ve výše uvedeném příkladuFileNotFoundException dědí z IOException. Takže pokud IOException byl první, pak by se místo toho zavolal., Pouze jeden blok úlovku je vyvolán, i když existuje více zápasů.

Jestliže máme System.IO.PathTooLongException IOException by zápas, ale kdybychom měliInsufficientMemoryException pak by se nic chytit, a to bude šířit do zásobníku.

chytit více typů najednou

je možné zachytit více typů výjimek se stejnýmcatch prohlášení.

Děkuji /u/Sheppard_Ra za návrh tohoto přidání.

házení zadané výjimky

můžete házet zadané výjimky v PowerShell., Namísto volání throw s string:

throw "Could not find: $path"

Použít výjimku akcelerátoru, jako je tento:

throw "Could not find: $path"

Ale musíte zadat zprávu, když budete dělat to, že způsob,.

můžete také vytvořit novou instanci výjimky, která má být hozena. Zpráva je volitelná, když to uděláteto proto, že systém má výchozí zprávy pro všechny vestavěné výjimky.

throw ::new()throw ::new("Could not find path: $path")

Pokud nepoužíváte PowerShell 5.0 nebo vyšší, musíte použít starší New-Object přístup.,

pomocí zadané výjimky můžete výjimku (nebo jiné) zachytit podle typu, jak je uvedeno v úvodní části.

Write-Error-Výjimka:

můžeme sečíst tyto zadané výjimky Write-Error a ještě můžeme catch chyby exceptiontype. Používání Write-Error, jako v těchto příkladech:

Pak se můžeme chytit.

catch { Write-Log $PSItem.ToString()}

velký seznam .NET výjimky

jsem sestavil seznam s pomocí Reddit/r/PowerShell společenství, které containshundreds .,Čisté výjimky k doplnění tohoto příspěvku.

  • velký seznam výjimek. Net

začnu hledáním tohoto seznamu výjimek, které mají pocit, že by byly vhodné pro mystituaci. Měli byste se pokusit použít výjimky v základně System jmenný prostor.

Výjimky jsou objekty

Pokud začnete používat hodně zadali výjimky, pamatujte, že jsou objekty. Různé výjimkymají různé konstruktory a vlastnosti., Pokud se podíváme na FileNotFoundExceptiondocumentation System.IO.FileNotFoundException vidíme, že můžeme předat zprávu a s filepath.

::new("Could not find file", $path)

A FileName vlastnost, která odhaluje, že cesta k souboru.

catch { Write-Output $PSItem.Exception.FileName}

měli byste se podívat na dokumentaci. NET pro jiné konstruktory a vlastnosti objektů.

Re-házení výjimku

Pokud se chystáte udělat v catch blok throw stejná výjimka, pak si nenechte catch., Měli byste pouze catch výjimku, kterou plánujete zvládnout nebo provést nějakou akci, když se to stane.

tam jsou časy, kdy chcete provést akci na výjimku, ale re-hodit výjimku sosomething downstream může vypořádat s ním. Mohli bychom napsat zprávu nebo zaznamenat problém poblíž místa, kde ho objevíme,ale problém dále vyřešíme.

catch{ Write-Log $PSItem.ToString() throw $PSItem}

je Zajímavé, že je můžeme nazvat throw v catch a znovu hází currentexception.,

catch{ Write-Log $PSItem.ToString() throw}

chceme znovu hodit výjimku, abychom zachovali původní informace o provedení, jako je číslo řádku source scriptand. Pokud v tomto okamžiku hodíme novou výjimku, skrývá se tam, kde začala výjimka.

Re-házení nový výjimka:

Pokud jste chytit výjimku, ale chcete hodit jiný, pak byste měli hnízdo na originalexception uvnitř nové. To umožňuje někomu v zásobníku přístup jako$PSItem.Exception.InnerException.

catch{ throw ::new('Could not access field',$PSItem.Exception)}

$PSCmdlet.,ThrowTerminatingError()

jedna věc, kterou nemám rád o používání throw raw výjimky je, že chyba messagepoints na throw prohlášení a označuje, že linka je místo, kde problém je.

Má chybovou zprávu řekni mi, že můj scénář je rozbité, protože jsem volal throw na řádku 31 je abad zpráva pro uživatele skriptu vidět. Neříká jim to nic užitečného.

Dexter Dhami poukázal na to, že k nápravě mohu použít ThrowTerminatingError().,

pokud předpokládáme, že ThrowTerminatingError() byla volána uvnitř funkce s názvem Get-Resource, pakto je chyba, kterou bychom viděli.

vidíte, jak ukazuje na funkci Get-Resource jako zdroj problému? To říká uživateli něco užitečného.

, Protože $PSItem ErrorRecord, můžeme také použít ThrowTerminatingError je to způsob, jak znovu hodit.,

catch{ $PSCmdlet.ThrowTerminatingError($PSItem)}

tím se změní zdroj chyby, aby se Rutiny a skrýt vestavby své funkce z uživatelů své Rutiny.

Zkuste lze vytvořit ukončení, chyby

Kirk Munro poukazuje na to, že nějaké výjimky jsou pouze ukončení chyby při spuštění uvnitřtry/catch blok. Zde je příklad, který mi dal, který generuje dělbu nulovou výjimkou runtime.

function Start-Something { 1/(1-1) }

pak ji vyvolat takhle vidět generovat chybu a stále výstup zprávy.,

&{ Start-Something; Write-Output "We did it. Send Email" }

ale umístěním stejného kódu do try/catch vidíme, že se stalo něco jiného.

try{ &{ Start-Something; Write-Output "We did it. Send Email" }}catch{ Write-Output "Notify Admin to fix error and send email"}

vidíme, že chyba se stala ukončení chyba a ne výstup první zprávu. Co se mi nelíbí, je to, že tento kód můžete mít ve funkci a funguje jinak, pokud někdo používá try/catch.

sám jsem se s tím nesetkal, ale je to rohový případ, o kterém je třeba vědět.

$PSCmdlet.,ThrowTerminatingError() uvnitř try/catch

Jeden nuance $PSCmdlet.ThrowTerminatingError() je, že vytváří ukončení chyba v yourCmdlet ale to se změní na non-ukončení chybě poté, co opustí své Rutiny. To ponechává burdenon volajícího vaší funkce rozhodnout, jak zvládnout chybu. Mohou jej vrátit zpět do aterminating chyby pomocí -ErrorAction Stop nebo volat z try{...}catch{...}.,

Veřejné funkce šablony

Jeden poslední cestu jsem měl s mým rozhovor s Kirkem Munro byl, že on místechtry{...}catch{...} každý begin process end blok ve všech jeho advancedfunctions. V těchto obecných catch bloky, má jeden řádek pomocí$PSCmdlet.ThrowTerminatingError($PSItem) řešit všechny výjimky, takže jeho funkce.

function Start-Something{ param() process { try { ... } catch { $PSCmdlet.ThrowTerminatingError($PSItem) } }}

protože vše je v try prohlášení v rámci svých funkcí, vše funguje důsledně., Tototaké dává koncovému uživateli čisté chyby, které skryjí interní kód před generovanou chybou.

zaměřil jsem se natry/catch aspekt výjimek. Ale je tu jedna funkce dědictví, kterou musím zmínit, než to zabalíme.

a trap je umístěn ve skriptu nebo funkci zachytit všechny výjimky, které se dějí v tomto rozsahu. Když dojde k výjimce, provede se kód v trap a pak pokračuje normální kód. Pokud dojde k několika výjimkám, pak se past nazývá znovu a znovu.,

osobně jsem tento přístup nikdy nepřijal, ale vidím hodnotu ve skriptech admin nebo controller, které obsahují všechny výjimky, a pak stále pokračují v provádění.

závěrečné poznámky

přidání správného zacházení s výjimkami do skriptů je nejen činí stabilnějšími,ale také usnadňuje řešení těchto výjimek.

strávil jsem spoustu času mluvením throw protože je to základní koncept, když mluvíme o výjimcehandling., PowerShell nám také dal Write-Error který zpracovává všechny situace, kdy byste použilithrow. Takže si nemyslete, že po přečtení musíte používat throw.

Teď, když to mám vzít čas na to psát o zpracování výjimek v tomto detailu, jdu to přeřadit během používání Write-Error -Stop generovat chyby v mém kódu. Jdu také na radu takeKirk a udělám ThrowTerminatingError můj Goto Exception handler pro každou funkci.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *