Vraag Meerdere uitzonderingen tegelijkertijd vangen?


Het wordt afgeraden om gewoon te vangen System.Exception. In plaats daarvan moeten alleen de "bekende" uitzonderingen worden gepakt.

Nu leidt dit soms tot onnodige herhalende code, bijvoorbeeld:

try
{
    WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
    WebId = Guid.Empty;
}
catch (OverflowException)
{
    WebId = Guid.Empty;
}

Ik vraag me af: is er een manier om beide uitzonderingen te vangen en alleen de WebId = Guid.Empty één keer bellen?

Het gegeven voorbeeld is tamelijk eenvoudig, want het is maar een GUID. Maar beeld je je code in waarin je een object meerdere keren wijzigt en als een van de manipulaties op een verwachte manier mislukt, wil je de object. Als er echter een onverwachte uitzondering is, wil ik nog steeds dat hoger gooien.


1709
2017-09-25 20:56


oorsprong


antwoorden:


Vangst System.Exception en schakel de typen in

catch (Exception ex)            
{                
    if (ex is FormatException || ex is OverflowException)
    {
        WebId = Guid.Empty;
        return;
    }

    throw;
}

1788
2017-09-25 21:01



BEWERK: Ik ben het eens met anderen die zeggen dat vanaf C # 6.0 uitzonderingsfilters nu een prima manier zijn om te gaan: catch (Exception ex) when (ex is ... || ex is ... )

Behalve dat ik nog steeds een beetje een hekel heb aan de one-long-line lay-out en de code persoonlijk als volgt zou leggen. Ik denk dat dit net zo functioneel als esthetisch is, omdat ik geloof dat het het begrip verbetert. Sommigen zijn het daar misschien niet mee eens:

catch (Exception ex) when (
    ex is ...
    || ex is ...
    || ex is ...
)

ORIGINAL:

Ik weet dat ik een beetje laat ben op het feest hier, maar heilige rook ...

Terwijl je meteen doorhakt, dupliceert dit een eerder antwoord, maar als je echt een gemeenschappelijke actie wilt uitvoeren voor verschillende uitzonderingstypen en het geheel netjes binnen het bereik van de ene methode wilt houden, waarom niet gewoon een lambda gebruiken? / afsluiting / inline-functie om iets als het volgende te doen? Ik bedoel, de kans is redelijk goed dat je je realiseert dat je die sluiting gewoon een aparte methode wilt maken die je overal kunt gebruiken. Maar dan is het super eenvoudig om dat te doen zonder de rest van de code structureel te veranderen. Rechts?

private void TestMethod ()
{
    Action<Exception> errorHandler = ( ex ) => {
        // write to a log, whatever...
    };

    try
    {
        // try some stuff
    }
    catch ( FormatException  ex ) { errorHandler ( ex ); }
    catch ( OverflowException ex ) { errorHandler ( ex ); }
    catch ( ArgumentNullException ex ) { errorHandler ( ex ); }
}

Ik kan het niet helpen, maar vraag me af (waarschuwing: een beetje ironie / sarcasme voor de toekomst) waarom ga je in hemelsnaam al het mogelijke doen om in feite gewoon het volgende te vervangen:

try
{
    // try some stuff
}
catch( FormatException ex ){}
catch( OverflowException ex ){}
catch( ArgumentNullException ex ){}

... met een gekke variatie van de geur van deze volgende code, ik bedoel bijvoorbeeld, alleen om te doen alsof je een paar toetsaanslagen redt.

// sorta sucks, let's be honest...
try
{
    // try some stuff
}
catch( Exception ex )
{
    if (ex is FormatException ||
        ex is OverflowException ||
        ex is ArgumentNullException)
    {
        // write to a log, whatever...
        return;
    }
    throw;
}

Omdat het zeker niet automatisch leesbaarder is.

Toegegeven, ik liet de drie identieke exemplaren van /* write to a log, whatever... */ return; uit het eerste voorbeeld.

Maar dat is ongeveer mijn punt. Jullie hebben allemaal gehoord van functies / methoden, toch? Ernstig. Schrijf een gemeenschappelijk ErrorHandler functie en, zoals, noem het vanuit elk catch-blok.

Als je het mij vraagt, is het tweede voorbeeld (met de if en is trefwoorden) is zowel aanzienlijk minder leesbaar als tegelijkertijd aanzienlijk meer gevoelig voor fouten tijdens de onderhoudsfase van uw project.

De onderhoudsfase, voor iedereen die relatief nieuw is in programmeren, zal 98,7% of meer van de totale levensduur van je project omvatten, en de arme donder die het onderhoud doet, is bijna zeker iemand anders dan jij. En de kans is groot dat ze 50% van hun tijd besteden aan het vervloeken van je naam.

En natuurlijk blaft FxCop naar je en dat moet je ook ookvoeg een attribuut toe aan uw code dat precies zip te maken heeft met het lopende programma, en is alleen daar om FxCop te vertellen een probleem te negeren dat in 99,9% van de gevallen het helemaal correct is bij het markeren. En sorry, ik vergis me misschien wel, maar wordt dat "negeer" -attribuut eigenlijk niet in je app gecompileerd?

Zou het geheel zetten if test op één regel maakt het leesbaarder? Ik denk het niet. Ik bedoel, ik heb een andere programmeur eens lang geleden heftig betoogd dat meer code op één regel plaatsen "het sneller zou doen". Maar hij was natuurlijk keiharde noten. Probeerde hem uit te leggen (met een recht gezicht - wat uitdagend was) hoe de tolk of compiler die lange regel uit elkaar zou breken in discrete one-instruction-per-line statements - in wezen identiek aan het resultaat als hij vooruit was gegaan en maakte de code gewoon leesbaar in plaats van de compiler te slim af te zijn - had helemaal geen effect op hem. Maar ik dwaal af.

Hoe veel minder leesbaar krijgt dit wanneer u drie extra uitzonderingstypen toevoegt, een maand of twee vanaf nu? (Antwoord: het wordt een lot minder leesbaar).

Een van de belangrijkste punten, eigenlijk, is dat het grootste deel van het formatteren van de tekstuele broncode waar we allemaal dagelijks naar kijken, is om het echt, heel duidelijk voor andere mensen te maken wat er feitelijk gebeurt als de code loopt. Omdat de compiler de broncode verandert in iets totaal anders en zich niets aantrekt van de stijl van uw coderingsstijl. Dus alles-aan-één-lijn is ook helemaal niet goed.

Gewoon zeggen ...

// super sucks...
catch( Exception ex )
{
    if ( ex is FormatException || ex is OverflowException || ex is ArgumentNullException )
    {
        // write to a log, whatever...
        return;
    }
    throw;
}

370
2017-10-12 00:24



Zoals anderen hebben opgemerkt, kunt u een if verklaring in uw catch-blok om te bepalen wat er aan de hand is. C # 6 ondersteunt uitzonderingsfilters, dus het volgende werkt:

try { … }
catch (Exception e) when (MyFilter(e))
{
    …
}

De MyFilter methode kan er dan ongeveer zo uitzien:

private bool MyFilter(Exception e)
{
  return e is ArgumentNullException || e is FormatException;
}

Als alternatief kan dit allemaal inline worden gedaan (de rechterkant van de when-instructie moet alleen een booleaanse uitdrukking zijn).

try { … }
catch (Exception e) when (e is ArgumentNullException || e is FormatException)
{
    …
}

Dit is iets anders dan het gebruik van een if verklaring vanuit de catch blokkeren, met behulp van uitzonderingsfilters zal niet ontspan de stapel.

Je kan downloaden Visual Studio 2015 om dit te bekijken.

Als u Visual Studio 2013 wilt blijven gebruiken, kunt u het volgende nuget-pakket installeren:

Installatiepakket Microsoft.Net.Compilers

Op het moment van schrijven bevat dit ondersteuning voor C # 6.

Verwijzingen naar dit pakket zullen ervoor zorgen dat het project wordt gebouwd met behulp van de   specifieke versie van de C # en Visual Basic compilers vervat in de   pakket, in tegenstelling tot elke systeem geïnstalleerde versie.


239
2018-04-04 13:59



Helaas niet in C #, omdat je hiervoor een uitzonderingsfilter nodig hebt en C # die functie van MSIL niet blootstelt. VB.NET heeft deze mogelijkheid echter, bijvoorbeeld

Catch ex As Exception When TypeOf ex Is FormatException OrElse TypeOf ex Is OverflowException

Wat je zou kunnen doen is een anonieme functie gebruiken om je on-error code in te kapselen, en het dan in die specifieke catch-blokken te noemen:

Action onError = () => WebId = Guid.Empty;
try
{
    // something
}
catch (FormatException)
{
    onError();
}
catch (OverflowException)
{
    onError();
}

184
2017-09-25 21:03



Voor de volledigheid, sinds .NET 4.0de code kan worden herschreven als:

Guid.TryParse(queryString["web"], out WebId);

TryParse werpt nooit uitzonderingen en retourneert false als het formaat niet klopt, en stelt WebId in op Guid.Empty.


Sinds C # 7 u kunt voorkomen dat een variabele op een aparte regel wordt geïntroduceerd:

Guid.TryParse(queryString["web"], out Guid webId);

U kunt ook methoden maken voor het parseren van terugkerende tuples, die nog niet beschikbaar zijn in .NET Framework vanaf versie 4.6:

(bool success, Guid result) TryParseGuid(string input) =>
    (Guid.TryParse(input, out Guid result), result);

En gebruik ze als volgt:

WebId = TryParseGuid(queryString["web"]).result;
// or
var tuple = TryParseGuid(queryString["web"]);
WebId = tuple.success ? tuple.result : DefaultWebId;

Volgende nutteloze update van dit nutteloze antwoord komt wanneer deconstruction van out-parameters is geïmplementeerd in C # 12. :)


122
2018-04-13 12:18



Als je je applicatie kunt upgraden naar C # 6, heb je geluk. De nieuwe C # -versie heeft uitzonderingsfilters geïmplementeerd. Dus je kunt dit schrijven:

catch (Exception ex) when (ex is FormatException || ex is OverflowException) {
    WebId = Guid.Empty;
}

Sommige mensen denken dat deze code hetzelfde is als

catch (Exception ex) {                
    if (ex is FormatException || ex is OverflowException) {
        WebId = Guid.Empty;
    }
    throw;
}

Maar het is niet. Eigenlijk is dit de enige nieuwe functie in C # 6 die niet mogelijk is om te emuleren in eerdere versies. Eerst betekent een re-gooi meer overhead dan het overslaan van de catch. Ten tweede is het niet semantisch equivalent. De nieuwe functie behoudt de stapel intact wanneer u uw code fout opspoort. Zonder deze functie is de crashdump minder nuttig of zelfs nutteloos.

Zie een discussie hierover op CodePlex. En een voorbeeld van het verschil.


62
2018-04-01 12:29



Als u geen gebruik wilt maken van een if verklaring binnen de catch scopes, in C# 6.0 je kunt gebruiken Exception Filters syntaxis die al door de CLR werd ondersteund in voorbeelden van voorvertoningen, maar alleen in VB.NET/MSIL:

try
{
    WebId = new Guid(queryString["web"]);
}
catch (Exception exception) when (exception is FormatException || ex is OverflowException)
{
    WebId = Guid.Empty;
}

Deze code zal de Exception alleen als het een is InvalidDataException of ArgumentNullException.

Eigenlijk kun je daar eigenlijk elke voorwaarde in leggen when clausule:

static int a = 8;

...

catch (Exception exception) when (exception is InvalidDataException && a == 8)
{
    Console.WriteLine("Catch");
}

Merk op dat in tegenstelling tot een if verklaring binnen de catchde reikwijdte, Exception Filters kan niet gooien Exceptionsen wanneer ze dat doen, of wanneer de conditie dat niet is true, de volgende catch voorwaarde zal in plaats daarvan worden geëvalueerd:

static int a = 7;

static int b = 0;

...

try
{
    throw new InvalidDataException();
}
catch (Exception exception) when (exception is InvalidDataException && a / b == 2)
{
    Console.WriteLine("Catch");
}
catch (Exception exception) when (exception is InvalidDataException || exception is ArgumentException)
{
    Console.WriteLine("General catch");
}

Uitgang: algemene vangst.

Wanneer er meer dan één is true  Exception Filter - de eerste zal worden aanvaard:

static int a = 8;

static int b = 4;

...

try
{
    throw new InvalidDataException();
}
catch (Exception exception) when (exception is InvalidDataException && a / b == 2)
{
    Console.WriteLine("Catch");
}
catch (Exception exception) when (exception is InvalidDataException || exception is ArgumentException)
{
    Console.WriteLine("General catch");
}

Uitgang: vangst.

En zoals je kunt zien in de MSIL de code is niet vertaald naar if verklaringen, maar om Filters, en Exceptions kan niet worden weggegooid vanuit de gebieden die zijn gemarkeerd met Filter 1 en Filter 2 maar de filter gooide de Exception zal in plaats daarvan mislukken, ook de laatste vergelijkingswaarde die naar de stapel is geduwd vóór de endfilter commando bepaalt het succes / falen van het filter (Catch 1  XOR  Catch 2 zal dienovereenkomstig uitvoeren):

Exception Filters MSIL

Ook specifiek Guid heeft de Guid.TryParse methode.


26
2017-10-07 17:31