[C#] manier om fouten af te vangen zonder try/catch

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

  • Guus2005
  • Registratie: Juli 2019
  • Laatst online: 31-01-2023
Veel ervaring met vba en ben nu C# aan het leren.

Met een try/catch blok vang je fouten op. Wat gebeurt er met de fouten als je zo'n blok niet gebruikt? Wordt de gebruiker er dan gelijk mee lastig gevallen of is er nog een manier om dat te doen?

Bedankt!

Beste antwoord (via Guus2005 op 09-07-2019 09:05)


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Het ligt allemaal een beetje subtieler...

Je kunt met een try/catch "lokaal" een fout vangen, of je kunt de fout hogerop in je callstack alsnog vangen. En je kunt 'm ook helemaal naar boven in je callstack laten bubbelen; uiteindelijk heb je dan nog een 'laatste kans' om een Uncaught Exception Handler te implementeren. Dat is zo'n beetje de plek waar je applicatie op 't punt staat te crashen; je kunt daar nog wat logging doen of andere noodzakelijke zaken en dan 'gecontroleerd' crashen, of de gebruiker confronteren met een melding of...

Doe je dat niet dan zal .Net je met een standaard melding confronteren en daarna zal je applicatie crashen.

Dit alles heeft Microsoft allemaal prima gedocumenteerd. Ik sluit me dan ook aan bij @Creepy: wat heb je zelf al gezocht, geprobeerd, gevonden? Een tip voor een volgende keer: hanteer even onze Quickstart bij het openen van een topic.

[ Voor 27% gewijzigd door RobIII op 08-07-2019 12:23 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Alle reacties


Acties:
  • +5 Henk 'm!

  • CH4OS
  • Registratie: April 2002
  • Niet online

CH4OS

It's a kind of magic

Wat wil je precies bereiken? Ik mis even waar je met de vraag uiteindelijk naar toe wilt.
In het kader van logging en debugging lijkt het mij ook verstandiger om exceptions netjes te catchen en te verwerken.

[ Voor 40% gewijzigd door CH4OS op 08-07-2019 12:01 ]


Acties:
  • +1 Henk 'm!

  • MrMonkE
  • Registratie: December 2009
  • Laatst online: 11-05 15:45

MrMonkE

★ EXTRA ★

Dan crashed je app met een runtime error vanuit het Framework denk ik..

★ Lijkt joop.nl wel hier ★


Acties:
  • +4 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:15

Creepy

Tactical Espionage Splatterer

Laat het try/catch blok weg en kijk wat er gebeurd? Kleine moeite om te testen lijkt me. Waarom heb je dat nog niet gedaan?

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • +1 Henk 'm!

  • Khallouki
  • Registratie: Oktober 2006
  • Laatst online: 22:00
"Uncaught" Exception error krijg je dan.

Acties:
  • +3 Henk 'm!

  • Standeman
  • Registratie: November 2000
  • Laatst online: 15:44

Standeman

Prutser 1e klasse

Guus2005 schreef op maandag 8 juli 2019 @ 11:58:
Veel ervaring met vba en ben nu C# aan het leren.

Met een try/catch blok vang je fouten op. Wat gebeurt er met de fouten als je zo'n blok niet gebruikt? Wordt de gebruiker er dan gelijk mee lastig gevallen of is er nog een manier om dat te doen?

Bedankt!
Fouten vang je niet op een try/catch. Die vang je op door goed te programmeren en te testen. try/catch moet je gebruiken om exceptionele zaken op te vangen die met geen andere mogelijkheid kan ondervangen.

De gebruiker wordt inderdaad lastiggevallen omdat je programma crashed.

The ships hung in the sky in much the same way that bricks don’t.


Acties:
  • Beste antwoord
  • +7 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Het ligt allemaal een beetje subtieler...

Je kunt met een try/catch "lokaal" een fout vangen, of je kunt de fout hogerop in je callstack alsnog vangen. En je kunt 'm ook helemaal naar boven in je callstack laten bubbelen; uiteindelijk heb je dan nog een 'laatste kans' om een Uncaught Exception Handler te implementeren. Dat is zo'n beetje de plek waar je applicatie op 't punt staat te crashen; je kunt daar nog wat logging doen of andere noodzakelijke zaken en dan 'gecontroleerd' crashen, of de gebruiker confronteren met een melding of...

Doe je dat niet dan zal .Net je met een standaard melding confronteren en daarna zal je applicatie crashen.

Dit alles heeft Microsoft allemaal prima gedocumenteerd. Ik sluit me dan ook aan bij @Creepy: wat heb je zelf al gezocht, geprobeerd, gevonden? Een tip voor een volgende keer: hanteer even onze Quickstart bij het openen van een topic.

[ Voor 27% gewijzigd door RobIII op 08-07-2019 12:23 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Guus2005
  • Registratie: Juli 2019
  • Laatst online: 31-01-2023
Bedankt voor deze snelle antwoorden.

als ik dus in mijn main() een try/catch block zet zal die uiteindelijk alle fouten opvangen waar ik niet aan gedacht heb.

in VBA zet ik bovenin mijn code "On Error Goto Err_Handler" en vervolgens worden *alle* fouten daarin opgevangen.
In C# zet je alleen de code in een try/catch blok waar je problemen mee verwacht.
Het is me nu duidelijk. Bedankt!

(je kan nu ageren over het gebruik van goto in VBA maar dat is nu eenmaal de manier waarop VBA werkt.;)

Acties:
  • +2 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Guus2005 schreef op maandag 8 juli 2019 @ 12:34:
als ik dus in mijn main() een try/catch block zet zal die uiteindelijk alle fouten opvangen waar ik niet aan gedacht heb.
Dat kan, ja, maar daar is dus de uncaught exception handler voor...
Guus2005 schreef op maandag 8 juli 2019 @ 12:34:
in VBA zet ik bovenin mijn code "On Error Goto Err_Handler" en vervolgens worden *alle* fouten daarin opgevangen.
Dat is net zo min "goed". Fouten die je verwacht probeer je altijd zo lokaal mogelijk af te handelen (want daar heb je alle benodigde context). Als je een FileNotFoundException krijgt en je stuurt alles naar dezelfde ("globale") handler, hoe weet je dan waar het mis ging in je applicatie als je op 35 plaatsen aan I/O doet? De ene FileNotFound handel je anders af dan de andere, afhankelijk van de situatie.
Guus2005 schreef op maandag 8 juli 2019 @ 12:34:
In C# zet je alleen de code in een try/catch blok waar je problemen mee verwacht.
In alle talen. Ook VBA.
Guus2005 schreef op maandag 8 juli 2019 @ 12:34:
(je kan nu ageren over het gebruik van goto in VBA maar dat is nu eenmaal de manier waarop VBA werkt.;)
Nee hoor; je kunt ook in VBA "lokaal" fouten afhandelen, daar heb je onder andere "On error Goto X" en "On Error Goto 0" / "On Error Goto -1" voor. Het is (een stuk) omslachtiger dan try/catch(/finally), maar 't idee komt op 'tzelfde neer. Je kunt ook in VBA een 'try/catch' achtige constructie bouwen daarmee.

[ Voor 6% gewijzigd door RobIII op 08-07-2019 14:05 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Guus2005
  • Registratie: Juli 2019
  • Laatst online: 31-01-2023
Dank je wel RobIII voor je uitgebreide antwoord.
Ik zie net dat je zelfs in C# nog steeds de GOTO kan gebruiken. lol.

Ik ga de quickstart even lezen.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 14-04 17:27
Als je in C# leert over excepties, en wat er gebeurt wanneer je ze niet vangt, kijk dan ook naar "using" en "finally". Met name de "finally" kan verrassed zijn. Het effect van een "finally" hangt af van een "catch" elders. Dat kan zelfs een catch in een heel andere file zijn. Als je applicatie crasht omdat er helemaal geen catch is, dan werkt de finally ook niet meer.

En om het verwarrend te maken: "finally" runt vóór de "catch".

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 28-05 16:11
MSalters schreef op dinsdag 9 juli 2019 @ 15:08:
Als je applicatie crasht omdat er helemaal geen catch is, dan werkt de finally ook niet meer.

En om het verwarrend te maken: "finally" runt vóór de "catch".
TIL :D

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 22:59
MSalters schreef op dinsdag 9 juli 2019 @ 15:08:
Als je in C# leert over excepties, en wat er gebeurt wanneer je ze niet vangt, kijk dan ook naar "using" en "finally". Met name de "finally" kan verrassed zijn. Het effect van een "finally" hangt af van een "catch" elders. Dat kan zelfs een catch in een heel andere file zijn. Als je applicatie crasht omdat er helemaal geen catch is, dan werkt de finally ook niet meer.

En om het verwarrend te maken: "finally" runt vóór de "catch".
Dit is gewoon niet waar. Een "finally" runt ná de "catch".
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
try
{
    Console.WriteLine("try");
    throw new Exception("Oops");
}
catch (Exception ex)
{
    Console.WriteLine("catch");
}
finally
{
    Console.WriteLine("finally");
}
Geeft gewoon netjes de output die je verwacht.
try
catch
finally

Het enige waar je rekening mee moet houden is dat dit per try-catch blok geldt. Op het moment dat je de try-catch blokken (indirect) nested maakt, blijft de volgorde gewoon hetzelfde. Alleen gebeurt de "inner finally" vóór de outer catch, maar dat is ook logisch.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
try
{
    Console.WriteLine("outer try");
    try
    {
        Console.WriteLine("inner try");
        throw new Exception("Oops");
    }
    catch (Exception ex)
    {
        Console.WriteLine("inner catch");
        throw ex; // opzettelijke rethrow
    }
    finally
    {
        Console.WriteLine("inner finally");
    }
}
catch (Exception ex)
{
    Console.WriteLine("outer catch");
}
finally
{
    Console.WriteLine("outer finally");
}
Geeft dus zoals je verwacht:
outer try
inner try
inner catch
inner finally
outer catch
outer finally

Als het de exception niet zou rethrowen, wordt de outer catch niet aangeroepen maar de outer finally wél. Zou je het inner catch block weglaten, dan heb je het zelfde effect als wanneer je zou rethrowen in een catch.

Ook als je nested een exception throwed, maar deze nergens catched, worden alle finally blokken wel aangeroepen. Ondanks dat de applicatie vervolgens wel crashed.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("try");
            throw new Exception("Oops"); // uncaught
        }
        finally
        {
            Console.WriteLine("finally");
        }
    }
}
Geeft dus als output:
try
Unhandled Exception: System.Exception: Oops at ….
finally

Acties:
  • 0 Henk 'm!

  • mulder
  • Registratie: Augustus 2001
  • Laatst online: 28-05 21:53

mulder

ik spuug op het trottoir

Dat gedrag blijkt dus te verschillen in .Net Framework vs .Net Core zie ik nu, Core doet niet de finally in bovenstaande voorbeeld.... :/

oogjes open, snaveltjes dicht


Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 22:59
mulder schreef op dinsdag 9 juli 2019 @ 20:51:
Dat gedrag blijkt dus te verschillen in .Net Framework vs .Net Core zie ik nu, Core doet niet de finally in bovenstaande voorbeeld.... :/
Het blijkt ook niet eens daar aan te liggen, maar aan het besturingssysteem.
Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.

Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.
Ofwel, unexpected expected behavior 8)7

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
ThomasG schreef op dinsdag 9 juli 2019 @ 20:59:
[...]
Het blijkt ook niet eens daar aan te liggen, maar aan het besturingssysteem.

[...]
Ofwel, unexpected expected behavior 8)7
Mwah, ik vermoed meer dat het simpelweg een andere design filosofie is.
MS komt nog steeds van Windows weg en als zij daar vanaf het begin ingebouwd hebben dat er aan het einde altijd een finally kan komen, ook al doe je een "kill -9", dan is het logisch dat de clr daar vanuit gaat (en dus .Framework dat als standaard hanteert)

Terwijl als in linux een kill -9 een proces direct afschiet dan kan je in je clr programmeren wat je wilt, maar je krijgt die finally echt niet als er een kill -9 plaatsvind. Oftewel .Core kan het in dit soort gevallen niet garanderen...

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 14-04 17:27
ThomasG schreef op dinsdag 9 juli 2019 @ 20:40:
[...]
Dit is gewoon niet waar. Een "finally" runt ná de "catch".
Je geeft daar een voorbeeld in hetzelfde try-block, terwijl ik het expliciet had over een catch in een andere file (dus op hoger nivo). Dan runt de finally van de aangeroepen functie vóór de catch in de aanroepende functie.

(De context van de discussie was dus hoe de details van de aanroepende functie uitmaken; zonder die catch in de aanroepende functie werkt de finally binnen in de aangeroepen functie mogelijk niet )

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 14-04 17:27
Gomez12 schreef op woensdag 10 juli 2019 @ 01:48:
[...]

Mwah, ik vermoed meer dat het simpelweg een andere design filosofie is.
MS komt nog steeds van Windows weg en als zij daar vanaf het begin ingebouwd hebben dat er aan het einde altijd een finally kan komen, ook al doe je een "kill -9", dan is het logisch dat de clr daar vanuit gaat (en dus .Framework dat als standaard hanteert)
Een "kill -9" of een "TerminateProcess()" onder Windows zijn geen ven beiden excepties; dat is het punt niet.

Er is ook weinig fundamentele reden om te verwachten dat Linux iets geeft om CLR excepties, of Java excepties, of Javascript excepties, etcetera. Onder Linux is dat allemaal aan het proces zelf c.q. de runtime.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 22:59
MSalters schreef op donderdag 11 juli 2019 @ 11:57:
[...]

Je geeft daar een voorbeeld in hetzelfde try-block, terwijl ik het expliciet had over een catch in een andere file (dus op hoger nivo). Dan runt de finally van de aangeroepen functie vóór de catch in de aanroepende functie.

(De context van de discussie was dus hoe de details van de aanroepende functie uitmaken; zonder die catch in de aanroepende functie werkt de finally binnen in de aangeroepen functie mogelijk niet )
Het lijkt mij heel raar als het zo zou werken. Dat zou namelijk betekenen dat de exception afhandelijk ander gedrag vertoont als een exception een stapje hoger optreed. Uiterst merkwaardig.

Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 22:59
MSalters schreef op donderdag 11 juli 2019 @ 12:02:
[...]

Een "kill -9" of een "TerminateProcess()" onder Windows zijn geen ven beiden excepties; dat is het punt niet.

Er is ook weinig fundamentele reden om te verwachten dat Linux iets geeft om CLR excepties, of Java excepties, of Javascript excepties, etcetera. Onder Linux is dat allemaal aan het proces zelf c.q. de runtime.
Op Windows heeft het schijnbaar te maken met of Automatic debugging is ingeschakeld, waarna Windows voor alle applicaties stack unwinding doet als ze crashen. Systemen met Automatic Debugging ingeschakeld vertonen daardoor ander gedrag. Met stack unwinding vertoont het namelijk het gewenste en te verwachten gedrag, ook bij een uncaught exception. Zonder stack unwinding is het hocus-pocus of het wel of niet wordt aangeroepen.

In C++ is er overigens een vergelijkbaar dilemma. Bij een uncaught exception wordt de destructor in bepaalde omstandigheden niet aangeroepen. De fix daarvoor is hetzelfde als in C#, alles in je "main" wrappen in een try/catch statement zodat er geen "uncaught exceptions" zijn 8)7

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 14-04 17:27
ThomasG schreef op donderdag 11 juli 2019 @ 12:37:
[...]
Het lijkt mij heel raar als het zo zou werken. Dat zou namelijk betekenen dat de exception afhandelijk ander gedrag vertoont als een exception een stapje hoger optreed. Uiterst merkwaardig.
Tja, hoe anders doe je het? De "finally" in de aangeroepen functie moet draaien op het moment dat de top-of-stack naar de lokale functie wijst, en de "catch" in de aanroepende functie moet draaien na de stack unwind, wanneer de aangeroepen functie van de stack af is.

Dan heb je dus ook meteen de reden dat een unhandled exception zo'n uitzondering is. Zonder een stack unwind heb je geen duidelijke lijst van finally's die moeten draaien. Je ziet dan het verschil in aanpak. Je kunt één voor éen je stack frames unwinden. Of je begint met het zoeken naar een catch zodat je een lijst kan maken van alle stack frames tussen de throw en en de catch. In het eerste geval vind je pas uit dat er geen handler is nadat alle finally's zijn uitgevoerd, in het tweede geval faalt het maken van die lijst.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 14-04 17:27
ThomasG schreef op donderdag 11 juli 2019 @ 12:45:
[...]
In C++ is er overigens een vergelijkbaar dilemma. Bij een uncaught exception wordt de destructor in bepaalde omstandigheden niet aangeroepen. De fix daarvoor is hetzelfde als in C#, alles in je "main" wrappen in een try/catch statement zodat er geen "uncaught exceptions" zijn 8)7
Dat werkt nog steeds niet 100%. Excepties in de initializers van globals en excepties op andere threads komen geen van beiden in main() uit.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 22:59
MSalters schreef op donderdag 11 juli 2019 @ 14:32:
[...]

Tja, hoe anders doe je het? De "finally" in de aangeroepen functie moet draaien op het moment dat de top-of-stack naar de lokale functie wijst, en de "catch" in de aanroepende functie moet draaien na de stack unwind, wanneer de aangeroepen functie van de stack af is.

Dan heb je dus ook meteen de reden dat een unhandled exception zo'n uitzondering is. Zonder een stack unwind heb je geen duidelijke lijst van finally's die moeten draaien. Je ziet dan het verschil in aanpak. Je kunt één voor éen je stack frames unwinden. Of je begint met het zoeken naar een catch zodat je een lijst kan maken van alle stack frames tussen de throw en en de catch. In het eerste geval vind je pas uit dat er geen handler is nadat alle finally's zijn uitgevoerd, in het tweede geval faalt het maken van die lijst.
Ik heb er nog even naar gekeken, en: of wij begrijpen elkaar verkeerd, of het klopt niet wat je zegt. Er zijn drie mogelijke statements: try/catch, try/finally, en try/catch/finally. De volgorde is altijd: try/catch/finally, per statement. Als je een try/finally nest in een try/catch zal de finally voor de catch komen, omdat het in een andere scope is. En dat is logisch. Of dat nu in een andere methode, zelfde methode, of ander klasse of ander bestand is maakt niet uit. De volgorde blijft altijd hetzelfde, en dat geldt per try statement. Dat een finally voor een catch komt, is dan ook logisch en te verwachten. Je moet dat als losse dingen zien.

Waarschijnlijk bedoelen wij allebei hetzelfde, maar begrijpen wij elkaar niet 8)7
Pagina: 1