Welcome to Our Website

Kaikki mitä olet halunnut tietää poikkeukset

  • 05/23/2020
  • 14 minuuttia lukea
    • j
    • f
    • s

Virheiden käsittely on vain osa elämää, kun se tulee kirjallisesti koodi. Voimme usein tarkistaa ja validaattiedellytykset odotetun käyttäytymisen. Kun odottamaton tapahtuu, siirrymme poikkeuskäsittelyyn., Voit helposti käsitellä poikkeuksia syntyy muiden ihmisten koodi tai voit luoda oman ownexceptions toisten käsitellä.

Huom.

alkuperäinen versio tämän artikkelin ilmestyi blogi kirjoittanut @KevinMarquette. ThePowerShell-tiimi kiittää Keviniä tämän sisällön jakamisesta kanssamme. Tutustu hänen blogi atPowerShellExplained.com.

Perus terminologiaa

– Meidän täytyy kattaa joitakin perus ehdot, ennen kuin voimme hypätä tämän yhden.

poikkeus

poikkeus on kuin tapahtuma, joka syntyy, kun normaali virheenkäsittely ei voi käsitellä asiaa.,Yrittää jakaa numero on nolla tai loppumassa muisti ovat esimerkkejä jotain, joka luo lisäksi. Joskus koodin tekijä luo poikkeuksia tietyille kysymyksille, kun niitä tapahtuu.

heitto ja saalis

kun poikkeus tapahtuu, sanomme, että poikkeus heitetään. Heitetyn poikkeuksen käsittelemiseksi sinun on pyydettävä sitä. Jos poikkeus heitetään, ja se ei ole kiinni jotain, käsikirjoitus stopsexecuting.

kutsupino

kutsupino on luettelo toisiaan soittaneista funktioista., Kun funktio kutsutaan, itgets lisätään pinoon tai listan alkuun. Kun toiminto poistuu tai palaa, se poistetaan pinosta.

Kun poikkeus heitetään, että call stack on valittu, jotta poikkeus handler catchit.

Päättämisestä ja ei-päättämisestä virheitä

poikkeus on yleensä päättämisestä virhe. Heitetty poikkeus joko jää kiinni tai se keskeyttää nykyisen teloituksen. Oletuksena, ei-päättämisestä virhe syntyy Write-Errorja lisää virheilmoituksen output stream ilman heittää poikkeus.,

tämä on koska Write-Error ja muut ei-päättämisestä virheet eivät laukaisecatch.

niellessä poikkeuksen

tällöin sattuu virhe vain sen tukahduttamiseksi. Tee tämä varoen, koska se voi tehdäkeskeinen kysymyksiä erittäin vaikeaa.

Basic command syntax

Tässä on nopea katsaus perus-poikkeusten käsittely-syntaksia käytetään PowerShell.

heitä

luodaksemme Oman poikkeustapahtumamme, heitämme poikkeuksen throw avainsanalla.,

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

Tämä luo runtime poikkeus, että on päättämisestä virhe. Se hoitaa catch vuonna acalling toiminnon tai poistuu script viestin, kuten tämä.

Write-Error-ErrorAction Lopettaa

mainitsin, että Write-Error ei heittää päättämisestä virhe oletusarvoisesti. Jos määrität-ErrorAction Stop, Write-Errorluo päättämisestä virhe, joka voi käsitelläcatch.,

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

Kiitos Lee Dailey muistuttaa siitä, käyttäen -ErrorAction Stop tällä tavalla.

Cmdlet -ErrorAction Lopettaa

Jos määrität -ErrorAction Stop tahansa kehittyneitä toiminto tai-cmdlet-komentoa, se kääntyy kaikki Write-Errorlausunnot osaksi päättämisestä virheitä, että lopettaa suorittamiseen tai jotka voidaan hoitaa catch.,

Start-Something -ErrorAction Stop

Try/Catch

tapa, poikkeusten käsittely toimii PowerShell (ja monet muut kielet) on että ensin try asection koodia, ja jos se heittää virhe, voit catch sitä. Tässä on nopea näyte.

catch script toimii vain jos on päättämisestä virhe. Jos try suorittaa oikein, thenit hyppää yli catch.,

Kokeilla/Vihdoin

Joskus sinun ei tarvitse käsitellä virheen, mutta silti on joitakin koodi, joka suoritetaan, jos exceptionhappens tai ei. A finally script tekee juuri niin.

Katso tästä esimerkistä:

milloin tahansa avaat tai liität resurssiin, se kannattaa sulkea. Jos ExecuteNonQuery() throwsan poikkeus, yhteys ei ole suljettu. Tässä on sama koodi try/finally lohkon sisällä.

tässä esimerkissä yhteys suljetaan, jos siinä on virhe. Se on myös suljettu, jos ei ole virhe., finally skripti kulkee joka kerta.

Koska et ole kiinni poikkeus, se saa edelleen levittävät puhelun pino.

Try/Catch/Lopuksi

Se on täysin voimassa, käyttää catch ja finally yhdessä. Useimmiten käytät jompaakumpaa, mutta voit löytää skenaarioita, joissa käytät molempia.

$PSItem

nyt kun saimme perusasiat pois alta, voimme kaivaa hieman syvemmälle.,

Sisälle catch lohkon, on automaattinen muuttuja ($PSItem tai $_) tyyppi ErrorRecord, joka sisältää tietoja lukuun ottamatta. Tässä on nopea katsaus joihinkin näppäimistöihin.

näissä esimerkeissä käytin virheellistä polkua ReadAllText luodakseni tämän poikkeuksen.

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

PSItem.ToString()

Tämä antaa sinulle puhtain viesti käytettäväksi hakkuut ja yleinen lähtö., ToString() isautomatically kutsutaan jos $PSItem on sijoitettu merkkijono.

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

$PSItem.InvocationInfo

Tämä ominaisuus sisältää muita tietoja kerätään PowerShell noin toiminto tai scriptwhere poikkeuksena oli heitetty. Tässä on InvocationInfo näytteestä poikkeus, että Icreated.

tärkeät yksityiskohdat täällä näyttää ScriptName, Line koodi ja ScriptLineNumbermissä vetoaminen alkoi.

$PSItem.,ScriptStackTrace

Tämä ominaisuus näyttää funktiokutsujen järjestyksen, joka sai sinut koodiin, jossa poikkeus ongeneroitu.

– olen vain soittamiseen toimintoja sama kirjoitus, mutta tämä olisi seurata puhelut, jos multiplescripts olivat mukana.

$PSItem.Poikkeus

Tämä on todellinen poikkeus, joka heitettiin.

$PSItem.Poikkeus.Viesti

Tämä on yleinen viesti, joka kuvaa ottamatta ja on hyvä lähtökohta whentroubleshooting. Useimmissa poikkeuksissa on oletusviesti, mutta ne voidaan myös asettaa johonkin mukautettuun, kun poikkeus heitetään.,

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

– Tämä on myös viesti palasi soitettaessa $PSItem.ToString() jos ei ole yksi asetettuErrorRecord.

$PSItem.Poikkeus.InnerException

poikkeukset voivat sisältää sisäisiä poikkeuksia. Tämä on usein silloin, kun koodin olet callingcatches poikkeus ja heittää eri poikkeus. Alkuperäinen poikkeus on sijoitettu uuteen poikkeukseen.

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

aion palata tähän myöhemmin, kun puhun uudelleen heittää poikkeuksia.

$PSItem.Poikkeus.,StackTrace

Tämä on StackTrace poikkeusta. Näytin ScriptStackTrace edellä, mutta tämä on forthe puhelut hallitun koodin.

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 )

saat tämän pinon jäljen vain, kun tapahtuma heitetään hallinnoidusta koodista. Soitan a: han .NETframework toiminto suoraan niin, että on kaikki mitä voimme nähdä tässä esimerkissä. Yleensä kun katsot pinojälkeä, etsit mihin koodisi pysähtyy ja järjestelmäpuhelut alkavat.

Työskentely poikkeukset

Siellä on enemmän poikkeuksia kuin syntaksi ja poikkeus ominaisuuksia.,

kirjoitettujen poikkeusten pyydystäminen

voit olla valikoiva pyydystämiäsi poikkeuksia lukuun ottamatta. Poikkeuksilla on tyyppi ja voit täsmentää poikkeustyypin, jonka haluat pyydystää.

poikkeuksen tyyppi on valittu kullekin catch lohkon, kunnes yksi löytyy, joka vastaa poikkeus.On tärkeää ymmärtää, että poikkeuksia voi periä muilta poikkeuksia. Yllä olevassa esimerkissäFileNotFoundException perii IOException. Joten jos IOException oli ensin, sitten kävisi nimeltään sijaan., Vain yhteen pyyntilohkoon vedotaan, vaikka otteluita olisi useita.

Jos meillä oli System.IO.PathTooLongException, IOException sopisi, mutta jos meillä oliInsufficientMemoryException sitten mikään ei olisi kiinni se ja se levittää jopa pino.

Kiinni useita tyyppejä samanaikaisesti

on mahdollista, kiinni useita lukuun ottamatta tyyppejä samalla catch lausunto.

Kiitos /u/Sheppard_Ra ehdottaa tämän lisäksi.

heitto kirjoitetut poikkeukset

voit heittää kirjoitetut poikkeukset Powershelliin., Sen sijaan, kutsuen throw merkkijono:

throw "Could not find: $path"

Käytä poikkeus kiihdytin, kuten tämä:

throw "Could not find: $path"

Mutta sinun täytyy määrittää viestin, kun teet niin.

voit myös luoda uuden poikkeuksen heitettäväksi. Viesti on valinnainen, kun olet tehdä tämä, koska järjestelmä on oletuksena viestit kaikki sisäänrakennettu poikkeuksia.

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

Jos et käytä PowerShell 5.0 tai uudempi, sinun täytyy käyttää vanhempaa New-Object lähestymistapaa.,

koneella kirjoitettua poikkeusta käyttäen sinä (tai muut) voit pyydystää poikkeuksen tyypin mukaan sellaisena kuin se on mainittu edellisessä jaksossa.

Write-Error-Poikkeus

– Voimme lisätä nämä kirjoitetaan poikkeukset Write-Error ja voimme silti catch virheitä, joita exceptiontype. Käyttää Write-Error kuten näissä esimerkeissä:

Sitten voimme saada sen kiinni, kuten tämä:

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

iso lista .NET poikkeukset

olen koonnut listaa avulla Reddit/r/PowerShell yhteisö, joka containshundreds kannalta .,Nettomääräiset poikkeukset täydentämään tätä virkaa.

  • iso lista .NET poikkeukset

aloitan hakemalla että lista poikkeuksia, jotka tuntuu, että ne olisi hyvä sovi mysituation. Base System nimiavaruudessa kannattaa yrittää käyttää poikkeuksia.

poikkeukset ovat objekteja

jos alat käyttää paljon kirjoitettuja poikkeuksia, muista, että ne ovat objekteja. Eri poikkeuksetovat erilaisia rakentajia ja ominaisuuksia., Jos katsomme FileNotFoundExceptiondocumentation varten System.IO.FileNotFoundException näemme, että voimme välittää viestin ja filepath.

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

Ja se on FileName ominaisuus, joka altistaa sen tiedoston polku.

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

kannattaa tutustua.Net-dokumentaatioon muiden rakentajien ja objektien ominaisuuksista.

Uudelleen heittää poikkeus

Jos kaikki aiot tehdä oman catch lohko on throw sama poikkeus, älä sitten catchsitä., Sinun pitäisi vain catch poikkeus, että aiot käsitellä tai suorittaa joitakin toimia, kun ithappens.

on aikoja, jolloin haluat suorittaa toiminnon poikkeuksella, mutta heittää uudelleen poikkeuksen sosomething alavirtaan voi käsitellä sitä. Voisimme kirjoittaa viestin tai kirjata ongelman lähelle sitä, missä wediscover se, mutta käsitellä asiaa pidemmälle pinon.

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

Mielenkiintoista kyllä, voimme kutsua throw sisällä catch ja uudelleen heittää currentexception.,

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

haluamme uudelleen heittää poikkeus säilyttää alkuperäisen suorituksen tiedot, kuten lähde scriptand rivin numero. Jos tässä vaiheessa heitämme uuden poikkeuksen, se piiloutuu sinne, mistä poikkeus alkoi.

heittää uuden poikkeuksen uudelleen

jos nappaat poikkeuksen, mutta haluat heittää toisen, niin sinun pitäisi pesiytyä uuteen poikkeukseen. Tämän avulla joku alas pino käyttää sitä$PSItem.Exception.InnerException.

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

$PSCmdlet.,ThrowTerminatingError()

yksi asia, että en pidä siitä, käyttäen throw raaka-poikkeuksia on, että virhe messagepoints klo throw julkilausuman ja ilmaisee, että rivi on missä ongelma on.

Ottaa virhe viesti kertoa minulle, että minun kirjoitus on rikki, koska soitin throw rivillä 31 on abad viesti käyttäjille käsikirjoitus nähdä. Se ei kerro heille mitään hyödyllistä.

Dexter Dhami huomautti, että voin käyttää ThrowTerminatingError() korjaamaan, että.,

Jos oletamme, että ThrowTerminatingError() oli nimeltään sisällä funktion kutsutaan Get-Resource, thenthis on virhe, että haluamme nähdä.

haluatko nähdä, miten se viittaa Get-Resource toiminto, koska ongelman lähde? Se kertoo theuserille jotain hyödyllistä.

Koska $PSItem on ErrorRecord voimme myös käyttää ThrowTerminatingError tällä tavalla uudelleen heittää.,

catch{ $PSCmdlet.ThrowTerminatingError($PSItem)}

Tämä muuttaa lähde virhe-Cmdlet-komentoa ja piilottaa sisäosat toiminto tarkasteltavien käyttäjille-Cmdlet-komentoa.

Kokeile luoda päättämisestä virheitä

Kirk Munro huomauttaa, että joitakin poikkeuksia lukuun ottamatta ovat vain päättämisestä virheitä, kun suoritetaan sisälletry/catch lohko. Tässä on esimerkki, jonka hän antoi minulle, joka luo kuilun nolla runtime poikkeus.

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

Sitten vedota sen näin nähdä se tuottaa virhe ja silti tulostaa viestin.,

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

Mutta asettamalla, että sama koodi sisälle try/catch näemme jotain muuta tapahtuu.

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

näemme, että virhe tulee päättämisestä virhe ja ei lähtö ensimmäinen viesti. Mitä en likeabout tämä yksi on, että voit saada tämän koodin toiminto, ja se toimii eri tavalla, jos someoneis käyttäen try/catch.

en ole itse törmännyt tämän kanssa ongelmiin, mutta se on nurkkatapaus olla tietoinen.

$PSCmdlet.,ThrowTerminatingError() sisällä try/catch

Yksi vivahde $PSCmdlet.ThrowTerminatingError() on, että se luo päättämisestä virhe sisällä yourCmdlet mutta se muuttuu ei-päättämisestä virhe jälkeen se lähtee-Cmdlet-komentoa. Tämä jättää burdenon soittaja toiminnon päättää, miten käsitellä virhe. He voivat muuttaa sen takaisin aterminating virhe käyttämällä -ErrorAction Stop tai soittamalla sen sisällä try{...}catch{...}.,

Julkinen toiminta malleja

Yksi viimeinen keino, minulla oli minun keskustelun Kirk Munro oli, että hän asettaatry{...}catch{...} noin joka begin, process ja end lohkon kaikki hänen advancedfunctions. Näissä generic kiinni lohkoja, hän on yhdellä rivillä käyttäen$PSCmdlet.ThrowTerminatingError($PSItem) käsitellä kaikkia poikkeuksia, jolloin hänen toiminnot.

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

Koska kaikki on try lausuman sisällä hänen toiminnot, kaikki toimii johdonmukaisesti., Tämä antaa myös puhtaat virheet loppukäyttäjälle, joka piilottaa sisäisen koodin syntyvältä virheeltä.

Ansa

olen keskittynyt try/catch osa poikkeuksia. Mutta tarvitsen yhden perintöominaisuuden, ennen kuin lopetamme tämän.

trap asetetaan skripti tai funktio ottaa kiinni kaikki poikkeukset, jotka tapahtuvat, että soveltamisalaa. Kun poikkeus tapahtuu, suoritetaan trap koodi, jonka jälkeen normaali koodi jatkuu. Jos poikkeuksia tapahtuu, niin ansa kutsutaan yhä uudelleen.,

itse en koskaan omaksunut tätä lähestymistapaa, mutta näen arvon admin-tai controller-skripteissä, jotka kirjaavat kaikki ja kaikki poikkeukset, sitten edelleen suorittaa.

loppuhuomautukset

asianmukaisen poikkeusten käsittelyn lisääminen skripteihisi paitsi tekee niistä vakaampia, myös tekee niiden vianmäärityksestä helpompaa.

– olen viettänyt paljon aikaa puhumalla throw koska se on keskeinen käsite, kun puhutaan exceptionhandling., PowerShell antoi meille myös Write-Error joka hoitaa kaikki tilanteet, joissa käyttäisitthrow. Joten älä usko, että sinun tarvitsee käyttää throw luettuasi tämän.

Nyt, että olen ottanut aikaa kirjoittaa siitä, poikkeusten käsittely tässä yksityiskohtaisesti, aion toswitch yli käyttäen Write-Error -Stop tuottaa virheitä minun koodi. Menen myös takekirkin neuvoihin ja teen ThrowTerminatingError minun Goto-poikkeuskäsittelijäni jokaiselle funktiolle.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *