Bir anda bir neçə istisnanı tutmaq?

Yalnız System.Exception tutmaq tövsiyə edilmir. Bunun əvəzinə yalnız "bilinən" istisnaları tutmalısınız.

İndi bu bəzən lazımsız təkrarlanan kodu gətirə bilər, məsələn:

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

Maraqlıdır: istisnaları həm tutmaq, həm də WebId = Guid.Empty çağırmaq üçün bir yol varmı?

Bu nümunə olduqca sadədir, çünki yalnız bir GUID . Ancaq obyekti bir neçə dəfə dəyişdiyiniz kodu təsəvvür edin və manipulyasiyalardan biri uğursuzsa, object "yenidən qurulmasını" istəyir. Ancaq gözlənilməz bir istisna varsa, mən hələ də daha yüksək etmək istəyirəm.

1795
25 сент. Michael Stum tərəfindən təyin edilən Sep 25 2008-09-25 23:56 '08 at 23:56 2008-09-25 23:56
@ 29 cavab

System.Exception və Enable System.Exception Catch

 catch (Exception ex) { if (ex is FormatException || ex is OverflowException) { WebId = Guid.Empty; return; } throw; } 
1854
26 сент. Jozef Daigle tərəfindən verilmiş cavab 26 sentyabr. 2008-09-26 00:01 '08 at 0:01 2008-09-26 00:01

EDIT: C # 6.0 ilə istisna filtreler artıq böyük olduğunu söyləyən başqaları ilə razıyam: catch (Exception ex) when (ex is ... || ex is ... ) exception catch (Exception ex) when (ex is ... || ex is ... )

Hələ də bir satır nizamdan nifrət edirəm və şəxsən aşağıda göstərildiyi kimi kodu yükləyin. Hesab edirəm ki, estetik baxımdan xoşagəlməz funksionaldır, çünki mən anlayışımı yaxşılaşdırıram. Bəziləri razı ola bilər:

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

ORIGINAL:

Buradakı bir partiyanın bir az gecikdiyini bilirəm amma müqəddəs tüstü ...

Düz ardıcıllıqla kəsilən bu tip bir əvvəlki cavabı təkrarlayır, amma həqiqətən bir neçə istisna növü üçün ümumi bir fəaliyyət göstərmək və hər şeyi eyni qaydada və səmərəli şəkildə saxlamağı istəyirsinizsə, niyə yalnız lambda / qısa / insert funksiyasını istifadə etmək üçün istifadə etməyin Aşağıdakı kimi bir şey? Demək istəmirəm ki, nəhayət, bu bağlamanı hər yerdə istifadə edə biləcəyiniz ayrı bir metod etmək istədiyini başa düşdüyünüz yaxşıdır. Amma sonra kodun qalan hissəsini struktur dəyişmədən bunu etmək çox asan olacaq. Sağ olsun?

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

Mən bütün bu səylərin əsasən aşağıdakıları əvəz etmək üçün niyə bütün yer üzündəki nəyə görə bir- birinə kömək edə bilərik? ( Xəbərdarlıq: bir az istehza / sarcasm)

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

... bir sonrakı kod qoxusuna bəzi çılpaq dəyişikliklər ilə bir nümunə deməkdir, yalnız bir neçə tuş vuruşunu saxlaya bilərsiniz.

 // 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

Çünki o, əlbəttə ki, avtomatik olaraq oxunmur.

Əlbəttə ki, üçü eyni nümunəni buraxdım: return; ilk nümunədən.

Amma bu mənim sualım. Funksiyalar / üsullar haqqında eşitdim, sağ? Bir tərəfdən şakalar. Ümumi funksiyanı ErrorHandler və məsələn, hər bir tutma blokundan çağırın.

Mənə soruşsanız, ikinci nümunə ( if və açar sözlərsə) çox az oxunan və eyni zamanda layihənin saxlanma mərhələsində çox daha çox səhv olacaq.

Proqrama nisbətən yeni olan hər kəs üçün saxlama mərhələsi layihənin ümumi ömrünün 98,7% və ya daha çoxunu təşkil edəcək və xidmətə cəlb olunan yoxsul şmuck demək olar ki, səndən başqa bir kəs olacaq və çox yaxşıdır işinizə vaxtının 50% -ni adını lənətlə sərf edəcəyik.

Və əlbəttə ki, FxCop sizə barks və buna görə də, siz kodunuza bir xüsusiyyət əlavə etməlisiniz ki, proqramı işləyən ilə tam şəkildə zəiflətmişdir və FXCop-un yalnız 99.9% -i mükəmməl düzgün olduğunu qeyd edərkən. Və üzr istəmirəm, səhv ola bilərəm, ancaq tətbiqinizə daxil edilməmiş əslində "ignore" xüsusiyyətidir?

Bir xətt üzrə testin tamamının yerləşdirilməsini daha oxunandır. Mən belə düşünmürəm. Demək istəmişəm ki, bir dəfə daha bir kod əlavə edərək "daha sürətli işləməyə" səbəb olacaq bir dəfə şiddətlə iddia edən başqa bir proqramçı var idi. Lakin, əlbəttə ki, o, dəhşətli çılpaq qoz idi. Ona izah etməyə çalışarkən (düz bir üzə - çətin idi), tərcüməçi və ya tərtibatçı bu uzun xəttin ayrı-ayrı lineer təlimatlara necə pozacağını - əslində, əgər getdi və nəticədə kodu oxunandır, kompilyatoru aldatmağa çalışmaq - bu heç də təsir etmədi. Amma diqqət çəkirəm.

Bir və ya iki ayda üç növ istisnalar əlavə edərkən nə qədər az oxunan olur? (Cavab: çox az okunabilir olur).

Əslində, əsas nöqtələrdən biri, biz hər gün nəzərdən keçirən mətn mənbəyi kodunun ən çox formatlanması, həqiqətən, kodun icra edildiyi əslində başqalarına həqiqətən bəlli olmasıdır. Derleyici, kaynak kodunu tamamen farklı bir şey halına çevirdiğinden ve kodu biçimlendirme stiline önem vermez. Beləliklə, hamısı bir-birinə bənzəyir.

Söyləyin ...

 // super sucks... catch( Exception ex ) { if ( ex is FormatException || ex is OverflowException || ex is ArgumentNullException ) { // write to a log, whatever... return; } throw; } 
399
12 окт. 12 oktyabrda Craig tərəfindən verilən cavab 2013-10-12 03:24 '13 'da 3:24' de 2013-10-12 03:24

Başqalarının qeyd etdiyinə görə, nə olacağını müəyyən etmək üçün tutmaq blokunuzun içindəki if ola bilər. C # 6 istisna filtreləri dəstəkləyir, beləliklə aşağıdakılar işləyəcək:

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

MyFilter metodu bu kimi bir şeyə baxa bilər:

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

Alternativ olaraq, bu hamısı inline keçirilə bilər (bənddə sadəcə məntiqi ifadə olduğu zaman sağ tərəf).

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

Bu catch if istifadə etməkdən fərqlənir və istisna filtreləri istifadə yığını təşviq etməyəcəkdir .

Visual Studio 2015- ni yoxlamaq üçün yükləyə bilərsiniz.

Visual Studio 2013 istifadə edərək davam etmək istəyirsinizsə, aşağıdakı nuget paketini yükləyə bilərsiniz:

Microsoft.Net.Compilers quraşdırma paketi

Yazı zamanı C # -a dəstək olacaq.

Bu paketə istinadlar hər hansı bir quraşdırılmış sistemdən fərqli olaraq paketdə olan C # və Visual Basic kompilyatorlarının xüsusi versiyasını istifadə edərək, layihənin yaradılmasına gətirib çıxaracaqdır.

266
04 апр. Cavab Joe 04 apr verilir . 2014-04-04 16:59 '14 at 16:59 2014-04-04 16:59

C # -də təəssüf ki, bunun üçün bir istisna filtreye ehtiyacınız var və C # bu MSIL funksiyasını açıqlamır. VB.NET bu xüsusiyyətə malikdir, baxmayaraq ki,

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

Nə edə biləriksə, səhv kodunu əhatə etmək üçün anonim funksiyanı istifadə edin və sonra bu xüsusi tutmaq bloklarında çağırın:

 Action onError = () => WebId = Guid.Empty; try { // something } catch (FormatException) { onError(); } catch (OverflowException) { onError(); } 
184
26 сент. Greg Beech tərəfindən verilmiş cavab 26 sentyabr. 2008-09-26 00:03 '08 saat 00:03 'da 2008-09-26 00:03

.NET 4.0- dan sonra tamamlama üçün kodu yenidən yaza bilərsiniz:

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

TryParse heç bir zaman istisnaları atır və saxta qaytarır; format düzgün deyilsə, WebId qəbulu Guid.Empty .


# 7 olduğundan, dəyişənə ayrı bir xətt daxil edə bilməzsiniz:

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

Ayrıca, 4.6 sürümünden .NET Framework'te henüz kullanılmayan döndürülen eşlemeleri ayrıştırmak üçün yöntemler oluşturabilirsiniz:

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

Bunları aşağıdakı kimi istifadə edin:

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

Aşağıdakı lazımsız yeniləmə bu yararsız reaksiyanın həyata parametrləri deconstruction C # 12 həyata keçirilir zaman baş verir :)

126
13 апр. Athari tərəfindən verilib 13 apreldə 2013-04-13 15:18 '13 saat 15:18 'da 2013-04-13 15:18

Proqramı C # -ə yüksəltmək mümkünsə, uğurlar arzulayırsınız. C # -in yeni versiyası istisna filtreləri tətbiq etmişdir. Buna görə yaza bilərsiniz:

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

Bəziləri bu kodun eyni olduğuna inanırlar

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

Ancaq bu deyil. Əslində, bu, əvvəlki versiyalarda emulated olan C # -də yeni xüsusiyyətdir. Birincisi, re-roll bir tutma atlama daha çox üstü deməkdir. İkincisi, bu semantik cəhətdən deyildir. Yeni bir xüsusiyyət, kodunuzu ayıkladığınızda istifadə olunmamış yığını saxlayır. Bu funksiyasız təcili sıfırlama daha az faydalı və ya hətta faydasızdır.

CodePlex haqqında bu suala dair müzakirəyə baxın. Və fərqi göstərən bir nümunə.

64
01 апр. Cavab Maniero tərəfindən verilir 01 Apr. 2015-04-01 15:29 '15 at 15:29 'də 2015-04-01 15:29

Əgər bir catch içindəki if istifadə etmək istəməsəniz , C# 6.0 , əvvəlcədən baxılmış CLR tərəfindən dəstəklənən Exception Filters sözdizimini istifadə edə bilərsiniz , lakin yalnız VB.NET / MSIL :

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

Bu kod yalnız bir InvalidDataException və ya ArgumentNullException olduğunda bir Exception tutacaq.

Əslində, bənddə deyilən when hər hansı bir vəziyyəti qoya bilərsiniz:

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

catch içərisindəki if fərqli olaraq, Exception Filters ata bilmir və onlar etdikləri zaman və ya vəziyyət true olmadıqda, aşağıdakı catch vəziyyəti qiymətləndiriləcəkdir:

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

Çıxış: ümumi tutmaq.

Birdən çox true Exception Filter olduğunda, birincisi qəbul edilir:

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

Çıxış: Catch.

MSIL , kod, if MSIL çevrilmir və Filters ve Exceptions Filter 1 ve Filter 2 işaretli alanlardan atılmıyor, fakat İstisnayı silmeden filtre başarısız olur ve önceki karşılaştırma değeri, endfilter komandasının endfilter uğurunu / uğursuzluğunu necə müəyyən endfilter ( Catch 1 XOR Catch 2 müvafiq olaraq icra ediləcək):

2019

07 окт. Tamirə verilmiş cavab Oct 07. 2015-10-07 20:31 '15 at 8:31 pm 2015-10-07 20:31

İstisna filtreleri artıq C # 6'da mövcuddur. Bunu edə bilərsiniz

 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 Cavab 11-14 iyul tarixində saat 16: 00-da 2018-07-11 16:12 Mat J tərəfindən verilir

Qəbul edilən cavab, məqbul qəbul edilə bilər, istisna olmaqla CodeAnalysis / FxCop ümumi istisna növünü tutduğundan şikayət edəcəkdir.

Bundan əlavə, "işarəsi" operatoru işini bir az azalda bilər.

CA1800: lazımsız bir şəkildə "operatorun nəticəsini" kimi qiymətləndirin "deyə düşünməyin), ancaq bunu edərsən, hər bir istisnayı ayrı olaraq çıxardığınızdan daha çox kod yazacaqsınız.

Hər halda, burada nə edəcəyəm:

 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 cavab 30 iyul 2010-cu il saat 20: 09-da Matt tərəfindən verilmişdir

Bu Mattin cavabıdır (bir az təmiz olduğumu hiss edirəm) ... üsulu istifadə edin:

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

Hər hansı digər istisnalar atılacaq və WebId = Guid.Empty; kodu WebId = Guid.Empty; silinməyəcək. Başqa istisnalarınızı proqramınızın uğursuz olmasını istəmirsinizsə, əlavə edin, bu digər iki tapşırıqdan sonra:

 ... 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 авг. cavab bsara 31 avqust verilir . 2012-08-31 23:51 '12 at 11:51 PM 2012-08-31 23:51

C # -də Exclusive filtreləri istifadə etmək məsləhətdir, burada bir nümunə:

  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 окт. cavab 04 oktyabrda verilir . 2015-10-04 10:51 '15 at 10:51 am 2015-10-04 10:51

@Misal

Kodunuzun bir qədər revizyon versiyası:

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

String müqayisələri çirkin və yavaş.

17
26 сент. Cavab FlySwat 26 sep tərəfindən verilir . 2008-09-26 00:01 '08 at 0:01 2008-09-26 00:01

Joseph Deigl'in cavabı yaxşı bir həlldir, amma aşağıdakı quruluşu bir az daha dəqiq və daha az səhv meylli tapdım.

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

Bir ifadəni çevirmək üçün bir neçə üstünlük var:

  • Geri qaytarma bəyannaməsi tələb olunmur
  • Kodu iç içə deyil
  • Yusifin qərarı ilə ifadə olunan ifadədən ayrılan "çıxmaq" və ya "qayıtmaq" sözlərini unutma riski yoxdur.

Hətta bir xəttə qatıla bilər (baxmayaraq ki, çox gözəl deyil).

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

Düzenle: C # 6.0'da süzgəc sintaksisini bir az daha təmiz hala gətirəcək və hər hansı bir həllin üzərində bir sıra digər üstünlükləri ehtiva edəcək . (hər şeydən əvvəl yığını zərərsiz buraxın)

C # 6.0 sözdizimini istifadə edərək eyni problemin necə göründüyü belədir:

 catch(Exception ex) when (ex is SomeException || ex is OtherException) { // Handle exception } 
16
08 дек. Cavab Stefan T 08 dec tərəfindən verilir . 2014-12-08 23:31 '14 at 23:31 2014-12-08 23:31

C # 7 ilə, Michael Stum-dan cavab şifrə bəyanatının okunabilirliyini qoruyaraq yaxşılaşdırıla bilər:

 catch (Exception ex) { switch (ex) { case FormatException _: case OverflowException _: WebId = Guid.Empty; break; default: throw; } } 
14
05 янв. Cavab Fabian 05 yanvar verilir . 2018-01-05 14:43 '18 saat 02:43 'da 2018-01-05 14:43

Necə olar?

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

Xəbərdarlıq və xəbərdarlıq: Başqa bir görünüş, funksional stil.

Bağlantı birbaşa sualınıza cavab vermir, ancaq bu kimi görünmək üçün genişləndirmək çətindir:

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

(Əsasən, özünü qaytarır başqa bir boş Catch yenidən yüklə təmin edir)

Niyə daha vacib bir sual budur. Düşünürəm ki, xərclər burada qalibiyyətdən üstündür :)

12
18 мая '13 в 14:28 2013-05-18 14:28 Cavab verilir nawfal May 18 '13 da 14:28 2013-05-18 14:28
 catch (Exception ex) { if (!( ex is FormatException || ex is OverflowException)) { throw; } Console.WriteLine("Hello"); } 
12
07 янв. Konstantin Spirin tərəfindən verilmiş cavab 07 Yan 2009-01-07 11:07 '09 at 11:07 'da 2009-01-07 11:07

2015-12-15 yeniləmə: C # üçün on123.ru.site/questions/687 / ... baxın. Dilində təmiz və indi standartdır.

Bir dəfə tutmaq və istisnaları silmək üçün daha zərif bir həll istəyən insanlar üçün aşağıda göstərildiyi kimi uzadma üsulunu istifadə edirəm.

Mən artıq bu məqamda kitabxanamda oldum, digər məqsədlər üçün yazılmışam, lakin istisnalar üzrə type yoxlayıram. Bundan əlavə, imho, bir qrup || daha təmiz görünür . Həm də qəbul edilən cavabdan fərqli olaraq, xüsusi istisnalarla işləməyi üstün edirəm, buna görə də ex is ... istənməyən davranış var, çünki ana siniflər valideyn növlərinə təyin olunur).

İstifadə

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

Səhv rəftarın tam nümunəsi (yeni bir konsol tətbiqinə kopyalanma)

 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

Поскольку мне казалось, что эти ответы только коснулись поверхности, я попытался копать немного глубже.

Итак, что мы действительно хотим сделать, это то, что не компилируется, скажем:

 // Won't compile... damn public static void Main() { try { throw new ArgumentOutOfRangeException(); } catch (ArgumentOutOfRangeException) catch (IndexOutOfRangeException) { // ... handle } 

Причина, по которой мы хотим этого, состоит в том, что мы не хотим, чтобы обработчик исключений обнаруживал то, что нам нужно в дальнейшем. Конечно, мы можем поймать Исключение и проверить "если", что делать, но, честно говоря, мы этого действительно не хотим. (FxCop, проблемы с отладчиком, уродство)

Итак, почему этот код не компилируется - и как мы можем его взломать таким образом, чтобы он был?

Если мы посмотрим на код, нам действительно нужно переслать вызов. Однако, согласно MS Partition II, блоки обработчика исключений IL не будут работать так, что в этом случае имеет смысл, поскольку это подразумевает, что объект "исключение" может иметь разные типы.

Или, чтобы написать его в коде, мы просим компилятор сделать что-то вроде этого (ну, это не совсем правильно, но это самое близкое, что я думаю):

 // Won't compile... damn try { throw new ArgumentOutOfRangeException(); } catch (ArgumentOutOfRangeException e) { goto theOtherHandler; } catch (IndexOutOfRangeException e) { theOtherHandler: Console.WriteLine("Handle!"); } 

Причина, по которой это не будет компилироваться, совершенно очевидна: какой тип и значение имел бы объект "$ exception" (который здесь хранится в переменных "e" )? То, как мы хотим, чтобы компилятор справлялся с этим, - это отметить, что общий базовый тип обоих исключений - это "Исключение" , используйте для переменной, которая содержит оба исключения, а затем обрабатывают только два исключенных исключения. То, как это реализовано в IL, является "фильтром", который доступен в VB.Net.

Чтобы заставить его работать на С#, нам нужна временная переменная с правильным базовым типом "Исключение" . Чтобы управлять потоком кода, мы можем добавить некоторые ветки. Burada:

  Exception ex; try { throw new ArgumentException(); // for demo purposes; won't be caught. goto noCatch; } catch (ArgumentOutOfRangeException e) { ex = e; } catch (IndexOutOfRangeException e) { ex = e; } Console.WriteLine("Handle the exception 'ex' here :-)"); // throw ex ? noCatch: Console.WriteLine("We're done with the exception handling."); 

Очевидными минусами этого являются то, что мы не можем правильно перебросить и, честно говоря, это довольно уродливое решение. Уродство может быть немного исправлено путем устранения ветвления, что делает решение немного лучше:

 Exception ex = null; try { throw new ArgumentException(); } catch (ArgumentOutOfRangeException e) { ex = e; } catch (IndexOutOfRangeException e) { ex = e; } if (ex != null) { Console.WriteLine("Handle the exception here :-)"); } 

Это оставляет только "повторный бросок". Чтобы это сработало, мы должны иметь возможность выполнять обработку внутри блока catch, и единственный способ сделать эту работу - захватывающим объектом "Исключение" .

В этот момент мы можем добавить отдельную функцию, которая обрабатывает различные типы исключений, используя разрешение перегрузки, или обрабатывать исключение. Оба имеют недостатки. Чтобы начать, вот способ сделать это с помощью вспомогательной функции:

 private static bool Handle(Exception e) { Console.WriteLine("Handle the exception here :-)"); return true; // false will re-throw; } public static void Main() { try { throw new OutOfMemoryException(); } catch (ArgumentException e) { if (!Handle(e)) { throw; } } catch (IndexOutOfRangeException e) { if (!Handle(e)) { throw; } } Console.WriteLine("We're done with the exception handling."); 

И другое решение - поймать объект Exception и обработать его соответствующим образом. Наиболее буквальный перевод для этого, основанный на контексте выше, таков:

 try { throw new ArgumentException(); } catch (Exception e) { Exception ex = (Exception)(e as ArgumentException) ?? (e as IndexOutOfRangeException); if (ex != null) { Console.WriteLine("Handle the exception here :-)"); // throw ? } else { throw; } } 

Итак, заключаем:

  • Если мы не хотим повторять бросок, мы можем подумать об улавливании правильных исключений и их временном хранении.
  • Если обработчик прост и мы хотим повторно использовать код, лучшим решением является, возможно, введение вспомогательной функции.
  • Если мы хотим повторить бросок, у нас нет выбора, кроме как поместить код в обработчик catch Exception, который нарушит FxCop и ваши отлаживающие нечеткие исключения.
7
ответ дан atlaste 21 окт. '14 в 12:44 2014-10-21 12:44

Итак, вы повторяете много кода в каждом переключателе исключений? Похоже, что извлечение метода будет идеей Бога, не так ли?

Итак, ваш код сводится к следующему:

 MyClass instance; try { instance = ... } catch(Exception1 e) { Reset(instance); } catch(Exception2 e) { Reset(instance); } catch(Exception) { throw; } void Reset(MyClass instance) {  } 

Интересно, почему никто не заметил дублирование кода.

Из С# 6 вы также имеете фильтры исключений , как уже упоминалось другими. Таким образом, вы можете изменить приведенный выше код:

 try { ... } catch(Exception e) when(e is Exception1 || e is Exception2) { Reset(instance); } 
6
ответ дан HimBromBeere 22 сент. '16 в 14:40 2016-09-22 14:40

Это классическая проблема, с которой сталкиваются каждый разработчик С#.

Позвольте мне разбить ваш вопрос на 2 вопроса. Первый,

Можно ли сразу улавливать несколько исключений?

Короче говоря, нет.

Это приводит к следующему вопросу:

Как избежать дублирования кода, учитывая, что я не могу поймать несколько типов исключений в одном блоке catch()?

Учитывая ваш конкретный образец, где значение fall-back дешево для построения, мне нравится выполнять следующие шаги:

  • Инициализировать WebId до значения возврата.
  • Построить новый указатель во временной переменной.
  • Установите WebId для полностью созданной временной переменной. Сделайте это окончательным утверждением блока try {}.

Итак, код выглядит так:

 try { WebId = Guid.Empty; Guid newGuid = new Guid(queryString["web"]); // More initialization code goes here like // newGuid.x = y; WebId = newGuid; } catch (FormatException) {} catch (OverflowException) {} 

Если какое-либо исключение выбрано, то WebId никогда не будет установлен на полуконструированное значение и останется Guid.Empty.

Если построение значения возврата является дорогостоящим, и сброс значения намного дешевле, я бы переместил код reset в свою собственную функцию:

 try { WebId = new Guid(queryString["web"]); // More initialization code goes here. } catch (FormatException) { Reset(WebId); } catch (OverflowException) { Reset(WebId); } 
6
ответ дан Jeffrey Rennie 15 нояб. '17 в 23:27 2017-11-15 23:27

Может быть, попытайтесь сохранить свой код простым, например, поместив общий код в метод, как и в любой другой части кода, который не находится внутри предложения catch?

Məsələn:

 try { // ... } catch (FormatException) { DoSomething(); } catch (OverflowException) { DoSomething(); } // ... private void DoSomething() { // ... } 

Просто как бы я это сделал, пытаясь найти простое красивое узоры

4
ответ дан Żubrówka 23 янв. '18 в 17:02 2018-01-23 17:02

Хотел добавить мой короткий ответ на этот уже длинный поток. Что-то, о чем не упоминалось, это порядок приоритета операторов catch, более конкретно вам нужно знать о масштабах каждого типа исключения, которое вы пытаетесь поймать.

Например, если вы используете исключение "catch-all" как Exception , оно будет преследовать все остальные команды catch, и вы, очевидно, получите ошибки компилятора, однако, если вы отмените заказ, вы можете связать свой улов (бит анти-шаблона, я думаю), вы можете поместить в конец все Исключение , и это будет захват любых исключений, которые не удовлетворяли бы выше в вашей попытке. блок catch:

  try { // do some work here } catch (WebException ex) { // catch a web excpetion } catch (ArgumentException ex) { // do some stuff } catch (Exception ex) { // you should really surface your errors but this is for example only throw new Exception("An error occurred: " + ex.Message); } 

Я очень рекомендую, чтобы люди просмотрели этот документ MSDN:

Иерархия исключений

4
ответ дан Tahir Khalid 16 апр. '17 в 18:51 2017-04-16 18:51

Заметьте, что я нашел один способ сделать это, но это больше похоже на материал для The Daily WTF :

 catch (Exception ex) { switch (ex.GetType().Name) { case "System.FormatException": case "System.OverflowException": WebId = Guid.Empty; break; default: throw; } } 
3
ответ дан Michael Stum 25 сент. '08 в 23:56 2008-09-25 23:56

Здесь стоит упомянуть. Вы можете ответить на несколько комбинаций (ошибка исключения и exception.message).

Я столкнулся с ситуационным сценарием при попытке бросить объект управления в datagrid с любым содержимым как TextBox, TextBlock или CheckBox. В этом случае возвращаемое исключение было таким же, но сообщение изменилось.

 try { //do something } catch (Exception ex) when (ex.Message.Equals("the_error_message1_here")) { //do whatever you like } catch (Exception ex) when (ex.Message.Equals("the_error_message2_here")) { //do whatever you like } 
0
ответ дан George 07 дек. '18 в 18:14 2018-12-07 18:14
 catch(ArithmeticException | ArrayIndexOutOfBounds | RunTimeException | Exception ex) { ex.printStackTrace(); } 

Вы должны ввести дополнительные особые исключения.. ie сначала подклассы, а затем суперклассы...

0
ответ дан Shubham soni 29 окт. '17 в 13:51 2017-10-29 13:51

Маленький умный твистер, возможно, не для реальной жизни, размещая здесь только ради другого варианта и видя, насколько уродливый он

  catch (Exception ex) { if (ex is FormatException || ex is OverflowException) {} else throw; WebId = Guid.Empty; } 
-1
ответ дан Konstantin Spirin 03 дек. '17 в 1:22 2017-12-03 01:22

Просто вызовите try и catch дважды.

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

Просто Простой!!

-13
ответ дан scholar guy 29 июля '16 в 7:42 2016-07-29 07:42

В С# 6.0 фильтры исключений - это улучшения для обработки исключений

 try { DoSomeHttpRequest(); } catch (System.Web.HttpException e) { switch (e.GetHttpCode()) { case 400: WriteLine("Bad Request"); case 500: WriteLine("Internal Server Error"); default: WriteLine("Generic Error"); } } 
-20
ответ дан Kashif 20 мая '15 в 10:48 2015-05-20 10:48

Другие вопросы по меткам или Задайте вопрос