Iš karto paimkite kelias išimtis?

Nerekomenduojama tiesiog sugauti System.Exception . Vietoj to, turėtumėte sugauti tik „žinomas“ išimtis.

Dabar tai kartais sukelia nereikalingą pakartotinį kodą, pavyzdžiui:

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

Įdomu: ar galima sugauti abi išimtis ir tik vieną kartą skambinti WebId = Guid.Empty ?

Šis pavyzdys yra gana paprastas, nes tai tik GUID . Bet įsivaizduokite kodą, kuriuo kelis kartus pakeisite objektą, ir jei viena iš manipuliacijų nepavyksta, norite „iš naujo nustatyti“ object . Tačiau, jei yra netikėta išimtis, aš vis dar noriu jį padidinti.

1795 m
25 сент. įkūrė Michael Stum, rugsėjo 25 d 2008-09-25 23:56 '08, 23:56, 2008-09-25 23:56
@ 29 atsakymai

„Catch System.Exception ir „Enable Types“

 catch (Exception ex) { if (ex is FormatException || ex is OverflowException) { WebId = Guid.Empty; return; } throw; } 
1854 m
26 сент. Joseph Daigle atsakymas 26 sept. 2008-09-26 00:01 '08 ne 0:01 2008-09-26 00:01

EDIT: Sutinku su kitais, kurie sako, kad su C # 6.0, išimčių filtrai dabar yra puikūs: catch (Exception ex) when (ex is ... || ex is ... )

Išskyrus tai, kad vis dar nekenčiu vieno eilutės išdėstymo ir asmeniškai įkeliu kodą, kaip parodyta žemiau. Manau, kad jis yra toks pat funkcionalus, kaip ir estetiškai, nes manau, kad tai pagerina supratimą. Kai kurie gali nesutikti:

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

ORIGINALAS:

Aš žinau, kad aš šiek tiek vėlu čia, bet šventam dūmui.

Pjovimas tiesiai į siekį, šis tipas kartoja ankstesnį atsakymą, bet jei tikrai norite atlikti bendrą veiksmą dėl kelių tipų išimčių ir išlaikyti viską tvarkingai ir tvarkingai pagal tą patį metodą, kodėl gi ne tik naudoti lambda / short / insert funkciją kažkas panašaus? Aš turiu galvoje, tai labai gerai, kad jūs galiausiai suprasite, kad jūs tik norite, kad šis uždarymas būtų atskiras metodas, kurį galite naudoti visur. Bet tada tai bus labai paprasta, nekeičiant likusio kodo struktūros. Gerai?

 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 ); } } 

Aš negaliu padėti, bet stebėtis ( įspėjimas: šiek tiek ironijos / sarkazmo į priekį), kodėl visos šios pastangos vyksta vietoje, kad iš esmės pakeistumėte šiuos dalykus:

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

... su kai kuriais beprotiškais šio kito kodo pokyčiais, aš turiu omenyje pavyzdį, tik apsimesti, kad išsaugosite keletą klavišų.

 // sorta sucks, let 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; } 
border=0

Kadangi jis, žinoma, nėra automatiškai skaitomas.

Žinoma, palikau tris vienodus return; iš pirmojo pavyzdžio.

Bet tai yra mano klausimas. Girdėjau apie funkcijas / metodus? Jokių klaidų. Parašykite bendrąją funkciją „ ErrorHandler ir, pavyzdžiui, iškvieskite jį iš kiekvieno blokavimo bloko.

Jei manęs paklaustumėte, antrasis pavyzdys (su raktiniais žodžiais „ if ir „ is ) bus daug mažiau suprantamas ir tuo pačiu metu bus daug daugiau klaidų jūsų projekto priežiūros fazėje.

Kiekvienam, kuris gali būti palyginti naujas programavimo laikotarpis, išlaikymo etapas bus 98,7% ar daugiau viso jūsų projekto gyvavimo trukmės, o prastas schmuckas, dalyvaujantis išlaikymo veikloje, beveik neabejotinai bus kitas nei jūs, ir yra labai geras tikimybė, kad jie išleis 50% savo laiko darbui, kuris prakeiks jūsų vardą.

Ir, žinoma, „FxCop“ jus užgniaužia, todėl į savo kodą turėtumėte pridėti atributą, turintį tiksliai su „zip“ su vykdoma programa, ir tik ten, kad pasakytumėte „FxCop“ ignoruoti, kad 99,9 proc. žymint. Ir atsiprašau, galėčiau būti neteisinga, bet ar šis „ignoruoti“ atributas faktiškai neįrašytas į jūsų paraišką?

Viso, if bandymas if atliktas vienoje eilutėje, leidžia ją geriau skaityti? Aš taip nemanau. Aš turiu omenyje, kad turėjau kitą programuotoją, kuris smarkiai teigė, kad daugiau kodų įtraukimas į vieną eilutę sukeltų „greičiau dirbti“. Bet, žinoma, jis buvo protingas riaušės. Bandydamas jam paaiškinti (su tiesiu veidu - kas buvo sunku), kaip vertėjas ar kompiliatorius nutrauktų šią ilgą eilutę į atskiras atskirų linijų instrukcijas - iš tikrųjų būtų identiškas rezultatui, jei jis eitų į priekį ir tiesiog padarytų kodą skaitomą, o ne stengtis pagundyti kompiliatorių - jis apskritai neturėjo įtakos. Bet aš išsiblaškau.

Kaip mažiau aišku, kai pridedate dar tris tipų išimtis per mėnesį ar du? (Atsakymas: jis tampa daug mažiau skaitomas).

Iš tiesų vienas iš pagrindinių dalykų yra tai, kad dauguma teksto šaltinio kodo, kurį mes visi peržiūriime, formatavimas yra, kad tai tikrai, tikrai akivaizdu kitiems žmonėms, kas iš tikrųjų atsitinka, kai kodas vykdomas. Kadangi kompiliatorius paverčia šaltinio kodą į visiškai skirtingą kodą ir nerūpi kodo formavimo stilius. Taigi taip pat ir viskas vienoje eilutėje.

Tiesiog pasakyk ...

 // super sucks... catch( Exception ex ) { if ( ex is FormatException || ex is OverflowException || ex is ArgumentNullException ) { // write to a log, whatever... return; } throw; } 
399
12 окт. Craigo atsakymas, pateiktas spalio 12 d 2013-10-12 03:24 '13, 3:24, 2013-10-12 03:24

Kaip kiti pabrėžė, jūs galite turėti savo if savo sugavimo bloke, kad nustatytumėte, kas vyksta. „C # 6“ palaiko išimčių filtrus, todėl veiks toliau:

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

MyFilter metodas gali atrodyti taip:

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

Kita vertus, tai gali būti padaryta inline (dešinėje pusėje, kai sąlyga tiesiog turi būti loginė išraiška).

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

Tai skiriasi nuo „ if naudojant „ catch , o išskyrimo filtrų naudojimas nepalaiko kamino.

Visual Studio 2015“ galite atsisiųsti ir patikrinti.

Jei norite tęsti „Visual Studio 2013“ naudojimą, galite įdiegti šį „nuget“ paketą:

„Microsoft.Net.Compilers“ diegimo paketas

Rašymo metu tai apims C # 6 palaikymą.

Nuoroda į šį paketą leis sukurti projektą, naudojant konkrečią paketo „C #“ ir „Visual Basic“ kompiliatorių versiją, skirtingai nei bet kuri įdiegta sistema.

266
04 апр. atsakymas pateikiamas Joe 04 balandžio. 2014-04-04 16:59 '14 at 16:59 2014-04-04 16:59

Deja, ne C #, nes tam reikia išimties filtro, o C # neatskleidžia šios MSIL funkcijos. VB.NET turi šią funkciją, nors, pavyzdžiui,

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

Ką galite padaryti, naudokite anoniminę funkciją, kad įterptumėte klaidos kodą, ir paskambinkite jį šiuose konkrečiuose sugavimo blokuose:

 Action onError = () => WebId = Guid.Empty; try { // something } catch (FormatException) { onError(); } catch (OverflowException) { onError(); } 
184
26 сент. atsakymas, kurį pateikė Greg Beech 26 sept. 2008-09-26 00:03 '08 0:03 2008-09-26 00:03

Dėl išsamumo, nes .NET 4.0 kodą galima perrašyti kaip:

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

TryParse niekada neišmeta išimčių ir grąžina klaidingą, jei formatas neteisingas, WebId nustatymas yra Guid.Empty .


Kadangi C # 7 , negalite įvesti kintamojo atskiroje eilutėje:

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

Taip pat galite sukurti metodus, kaip analizuoti grąžintas rinkmenas, kurios dar nėra .NET Framework versijoje nuo 4.6 versijos:

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

Naudokite juos taip:

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

Šis nenaudingas atsakymas į šį nenaudingą atsakymą įvyksta tada, kai parametrai „C-12“ įgyvendinami iš išorės parametrų. :)

126
13 апр. Athari atsakymas, pateiktas balandžio 13 d 2013-04-13 15:18 '13, 15:18, 2013-04-13 15:18

Jei galite atnaujinti programą „C # 6“, tu esi laimingas. Nauja C # versija įdiegė išimčių filtrus. Todėl galite rašyti:

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

Kai kurie mano, kad šis kodas yra toks pat, kaip

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

Bet tai ne. Tiesą sakant, tai yra vienintelė nauja C # 6 funkcija, kuri negali būti imituojama ankstesnėse versijose. Pirma, pakartotinis ritinys reiškia daugiau pridėtinių nei praleidimas. Antra, tai nėra semantiškai lygiavertė. Nauja funkcija paleidžia nepanaudotą kaminą, kai derinate savo kodą. Be šios funkcijos, avarinis atstatymas yra mažiau naudingas ar net nenaudingas.

Žr. Diskusiją šiuo klausimu „CodePlex“ . Ir pavyzdys, rodantis skirtumą .

64
01 апр. Atsakymą pateikė Maniero 01 Bal. 2015-04-01 15:29 '15 15:29 2015-04-01 15:29

Jei nenorite naudoti „ if , esančio „ C# 6.0 , galite naudoti „ Exception Filters sintaksę , kurią CLR jau palaikė peržiūros metu, tačiau tik VB.NET / MSIL :

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

Šis kodas bus Exception tik tada, kai tai yra InvalidDataException arba ArgumentNullException .

Tiesą sakant, jūs galite įdėti bet kokią sąlygą, when ši sąlyga:

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

Atkreipkite dėmesį, kad, priešingai nei if esantis catch , Exception Filters negali Exceptions , o kai tai daroma arba kai sąlyga nėra true , vietoj to bus vertinama ši catch sąlyga:

 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"); } 

Išėjimas: bendras sugavimas.

Kai yra daugiau nei vienas true Exception Filter , pirmasis bus priimtas:

 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"); } 

Išėjimas: sugavimas.

Ir kaip matote MSIL , kodas nėra išverstas, if ir Filters ir Exceptions negali būti išmesti iš sričių, pažymėtų Filter 1 ir Filter 2 filtru Filter 2 tačiau filtro išmetimo Exception nepavyks, o taip pat paskutinė lyginamoji vertė, kuri buvo įkelta į kaminą prieš kaip endfilter komanda endfilter filtro sėkmę / gedimą ( Catch 1 XOR Catch 2 bus atlikta atitinkamai):

2019

07 окт. Tamir Vered atsakymas . 2015-10-07 20:31 '15, 8:31 pm 2015-10-07 20:31

Išimčių filtrai dabar yra C # 6+. Jūs galite tai padaryti

 try { WebId = new Guid(queryString["web"]); } catch (Exception ex) when(ex is FormatException || ex is OverflowException) { WebId = Guid.Empty; } 
26
11 июля '18 в 16:12 2018-07-11 16:12 atsakymą pateikė Mat J , liepos 11 d., 18 val., 12 val., 2018-07-11, 16:12

Priimtinas atsakymas atrodo priimtinas, išskyrus tai, kad „CodeAnalysis“ / „FxCop“ skundžiasi, kad sugautas bendrasis išimtis.

Be to, atrodo, kad operatorius „gali“ gali šiek tiek pabloginti našumą.

CA1800: neišmeskite nereikalingai sakydami, kad „pagalvokite apie operatoriaus rezultato testavimą“, tačiau jei tai padarysite, rašysite daugiau kodo nei tuo atveju, jei išimsite kiekvieną išimtį atskirai.

Bet kokiu atveju, ką darysiu:

 bool exThrown = false; try { // Something } catch (FormatException) { exThrown = true; } catch (OverflowException) { exThrown = true; } if (exThrown) { // Something else } 
19
30 июля '10 в 20:09 2010-07-30 20:09 atsakymą pateikė Mattas liepos 30 d. 10 val. 20:09 2010-07-30 20:09

Tai yra Matt atsakymas (manau, kad tai šiek tiek švaresnis) ... naudokite metodą:

 public void TryCatch(...) { try { // something return; } catch (FormatException) {} catch (OverflowException) {} WebId = Guid.Empty; } 

Visos kitos išimtys bus išmestos, o „ WebId = Guid.Empty; kodas WebId = Guid.Empty; nebus ištrintas. Jei nenorite, kad programoje nepavyktų kitų išimčių, tiesiog pridėkite tai po dviejų kitų sugavimų:

 ... catch (Exception) { // something, if anything return; // only need this if you follow the example I gave and put it all in a method } 
18
31 авг. atsakymas pateikiamas bsara 31 rug . 2012-08-31 23:51 '12 at 11:51 PM 2012-08-31 23:51

C # 6, rekomenduojama naudoti išskirtinius filtrus, čia yra pavyzdys

  try { throw new OverflowException(); } catch(Exception e ) when ((e is DivideByZeroException) || (e is OverflowException)) { // this will execute iff e is DividedByZeroEx or OverflowEx Console.WriteLine("E"); } 
17
04 окт. atsakymas duotas SHM 04 okt. 2015-10-04 10:51 '15, 10:51 am 2015-10-04 10:51

@Micheal

Šiek tiek pataisyta kodo versija:

 catch (Exception ex) { Type exType = ex.GetType(); if (exType == typeof(System.FormatException) || exType == typeof(System.OverflowException) { WebId = Guid.Empty; } else { throw; } } 

Styginių palyginimas yra bjaurus ir lėtas.

17
26 сент. atsakymą pateikė „ FlySwat 26 sep“ . 2008-09-26 00:01 '08 ne 0:01 2008-09-26 00:01

Joseph Deigl atsakymas yra geras sprendimas, tačiau aš pastebėjau, kad ši struktūra šiek tiek tikslesnė ir mažiau klaidinga.

 catch(Exception ex) { if (!(ex is SomeException || ex is OtherException)) throw; // Handle exception } 

Išversti išraišką yra keletas privalumų:

  • Nereikalaujama grąžinimo ataskaitos
  • Kodas nėra įdėtas
  • Nėra jokios rizikos pamiršti žodžius „mesti“ arba „sugrįžti“, kurie yra atskirti nuo Juozapo sprendimo išraiškos.

Jis netgi gali būti sutrumpintas iki vienos linijos (nors ir ne labai gražus).

 catch(Exception ex) { if (!(ex is SomeException || ex is OtherException)) throw; // Handle exception } 

Redagavimas: Filtravimas C # 6.0 sistemoje padarys sintaksę šiek tiek švaresnę ir jame bus daug kitų privalumų, palyginti su dabartiniu sprendimu. (pirmiausia palikite kamino nepažeistą)

Štai kokia ta pati problema atrodytų naudojant C # 6.0 sintaksę:

 catch(Exception ex) when (ex is SomeException || ex is OtherException) { // Handle exception } 
16
08 дек. Atsakymą pateikė Stefan T 08 dec. 2014-12-08 23:31 '14, 23:31 2014-12-08 23:31

Su „C # 7“, atsakymas iš „Michael Stum“ gali būti pagerintas išlaikant perjungimo pareiškimo įskaitomumą:

 catch (Exception ex) { switch (ex) { case FormatException _: case OverflowException _: WebId = Guid.Empty; break; default: throw; } } 
14
05 янв. Atsakymas duotas Fabian 05 jan. 2018-01-05 14:43 '18, 14:43 pm 2018-01-05 14:43

Kaip apie

 try { WebId = Guid.Empty; WebId = new Guid(queryString["web"]); } catch (FormatException) { } catch (OverflowException) { } 
13
25 сент. Atsakymas duotas Maurice 25 Sep. 2008-09-25 23:57 '08 at 11:57 2008-09-25 23:57

Įspėjimas ir įspėjimas: Kita išvaizda, funkcinis stilius.

Ką nuoroda tiesiogiai neatsako į jūsų klausimą, tačiau yra nereikšminga išplėsti ją taip:

 static void Main() { Action body = () => { ...your code... }; body.Catch<InvalidOperationException>() .Catch<BadCodeException>() .Catch<AnotherException>(ex => { ...handler... })(); } 

(Iš esmės suteikia kitą tuščią „ Catch perkrovimą, kuris grąžina save)

Svarbesnis klausimas yra, kodėl. Nemanau, kad kaina yra didesnė už laimėjimus čia :)

12
18 мая '13 в 14:28 2013-05-18 14:28 atsakymas pateikiamas gegužės 18 d. 13 val. 14:28 2013-05-18 14:28
 catch (Exception ex) { if (!( ex is FormatException || ex is OverflowException)) { throw; } Console.WriteLine("Hello"); } 
12
07 янв. Konstantino Spirino atsakymas 07 Jan 2009-01-07 11:07 '09 at 11:07 2009-01-07 11:07

Atnaujinimas 2015-12-15: žr. ngn-wiki.ru.site/questions/687 / ... už C # 6. Tai švaresnis ir dabar standartinis kalba.

Žmonėms, kurie nori daugiau elegantiško sprendimo sugauti vieną kartą ir filtruoti išimtis, naudoju pratęsimo metodą, kaip parodyta žemiau.

Aš jau turėjau šį pratęsimą savo bibliotekoje, iš pradžių parašytą kitiems tikslams, tačiau jis puikiai veikė, kad patikrintų type išimčių atveju. Be to, imho, atrodo švaresnis nei || . Be to, priešingai nei priimtas atsakymas, aš norėčiau aiškų išimties tvarkymą, todėl ex is ... turi nepageidaujamą elgesį, nes atimtos klasės priskiriamos tėvų tipams.

Naudojimas

 namespace Common.FluentValidation { public static partial class Validate { /// <summary> /// Validates the passed in parameter matches at least one of the passed in comparisons. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="p_parameter">Parameter to validate.</param> /// <param name="p_comparisons">Values to compare against.</param> /// <returns>True if a match is found.</returns> /// <exception cref="ArgumentNullException"></exception> public static bool IsAnyOf<T>(this T p_parameter, params T[] p_comparisons) { // Validate p_parameter .CannotBeNull("p_parameter"); p_comparisons .CannotBeNullOrEmpty("p_comparisons"); // Test for any match foreach (var item in p_comparisons) if (p_parameter.Equals(item)) return true; // Return no matches found return false; } } } 

Pilnas klaidų apdorojimo pavyzdys (kopijavimas į naują konsolės programą)

 using System; using System.Collections.Generic; using Common.FluentValidation; using NUnit.Framework; namespace UnitTests.Common.Fluent_Validations { [TestFixture] public class IsAnyOf_Tests { [Test, ExpectedException(typeof(ArgumentNullException))] public void IsAnyOf_ArgumentNullException_ShouldNotMatch_ArgumentException_Test() { Action TestMethod = () => { throw new ArgumentNullException(); }; try { TestMethod(); } catch (Exception ex) { if (ex.GetType().IsAnyOf( typeof(ArgumentException),  typeof(FormatException), typeof(KeyNotFoundException))) { // Handle expected Exceptions return; } //else throw original throw; } } [Test, ExpectedException(typeof(OutOfMemoryException))] public void IsAnyOf_OutOfMemoryException_ShouldMatch_OutOfMemoryException_Test() { Action TestMethod = () => { throw new OutOfMemoryException(); }; try { TestMethod(); } catch (Exception ex) { if (ex.GetType().IsAnyOf( typeof(OutOfMemoryException), typeof(StackOverflowException))) throw;  } } } } 
10
ответ дан HodlDwon 28 нояб. '13 в 0:53 2013-11-28 00:53