Try-catch en exceptions in een API

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 06:48
Ik zit mij een beetje zorgen te maken over hoe ik exceptions moet 'doorgeven'. Doorgeven is natuurlijk zowieso niet echt de bedoeling, maar ik moet deze exceptions toch opvangen, resources vrijgeven indien mogelijk en de gebruiker (het programma, de class, de methode) die gebruikmaakt van mijn API ervan verwittigen dat niet alles loopt zoals het zou moeten. Nu werkt deze API intern met onder andere sockets en je kan daar op praktisch iedere function call een exception krijgen. Uiteraard werken deze sockets op een andere thread.

Nu programmeer ik een beetje op de manier hoe de C#.NET Webclient ook is opgebouwd: ****Async methode die een thread start die zijn ding doet en door middel van event delegates zijn resultaten kan uitvoeren. Voor dingen zoals 'klaar zijn' en progress doorgeven is het duidelijk, want klaar zijn doe je als je gedaan hebt wat er verwacht wordt. Maar errors kunnen overal optreden, als ik dit, even snel in elkaar geflanste stukje code hebt:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint iep = new IPEndPoint(IPAddress.Any, SpeedProtocol.BroadcastPort);
            sock.Bind(iep);

            EndPoint ep = iep;
            

            while ( !TimesUp() ) { //some function telling whether our time's up, just pseudocode
                byte[] data = new byte[4048];
                int recv = sock.ReceiveFrom(data, ref ep);

                // deserialize the bytes to a Protocol packet
                BinaryFormatter formatter = new BinaryFormatter();
                MemoryStream stream = new MemoryStream();
                stream.Write(data, 0, data.Length);
                stream.Seek(0, 0);
                Protocol packet = (Protocol) formatter.Deserialize(stream);

                Protocol dummy;
                bool found = this.TaskList.TryGetValue(packet.ServerIpAddress, out dummy);

                if ( !found ) {
                    this.TaskList.Add(packet.ServerIpAddress, packet);

                    TaskEventArgs eventArgs = new TaskEventArgs(packet.ServerIpAddress,
                                                                                              packet);
                    this.OnBroadcastDiscovered(eventArgs);
                }

                // determine whether we need to cancel
                if ( this.CancellationRequested ) {
                    sock.Shutdown(SocketShutdown.Receive);
                    sock.Close();

                    this.OnTaskComplete(new TaskCompleteEventArgs(this.TaskList, true));
                    return;
                }

                // next
            }

            this.OnTaskComplete(new TaskCompleteEventArgs(this.ResultList));

            // shut down socket and return
            sock.Shutdown(SocketShutdown.Both);
            sock.Close();
Op verschillende function calls kan je hier exceptions krijgen, maar naar mijn gevoel is het niet netjes om op iedere functie een try-catch neer te zetten met in de catch een OnError() en eventueel in de catch nog een Socket.Close(). Beter is het lijkt me om op basis van de documentatie te bepalen of je een exception kan krijgen, maar dan nog heb je kan op veel try-catch blokken en ik heb onderbuikgevoelens dat zoiets niet netjes is.

Nu heb ik hier wel Code Complete 2 liggen, oom ook hierin wordt geen 'way to go' aangeven. Super boek is het, en heeft mij veel brainvoer bezorgt maar hierover kan ik vreemd genoeg niets vinden. Wat is volgens mijn mededevvers 'the way to go'?

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

kijk eens naar de "using( ) { }" construct.

dit is eigenlijk zoveel als
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
using (X x = new X())
{
  // code
}

X x = new X
try
{
   // code
}
finally
{
   x.Dispose()
}


Het is zowiezo good practice om IDisposable te zijn als je non-managed resources hebt, anders laat je de GC het maar oplossen.

[ Voor 24% gewijzigd door H!GHGuY op 31-05-2009 08:41 ]

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 06:48
Yep, het using statement ben ik bekend mee, dat doe je gewoon zo:
C#:
1
2
3
4
5
6
ZwareResource z = new ZwareResource(); //try-catch hier

using (z)
{
    // use z
}


Maar hoe doe ik het dan met eventuele statements in het using block, ik kan moeilijk om iedere statement een try-catch zetten, iets verteld mij dat dat anders kan.

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Sebazzz schreef op zondag 31 mei 2009 @ 09:26:
Yep, het using statement ben ik bekend mee, dat doe je gewoon zo:
C#:
1
2
3
4
5
6
ZwareResource z = new ZwareResource(); //try-catch hier

using (z)
{
    // use z
}
C#:
1
2
3
4
5
6
7
8
9
10
11
12
try {
  using (ZwareResource z = new ZwareResource();)
  {
      // use z
  }
} catch (MyException ex) {
  //handle here
} catch (SomeException ex) {
  //handle here
} finally {
  //Do stuff here
}

Exceptions anders dan MyException en SomeException bubbelen gewoon door. Enkel de voor jou relevante exceptions worden afgehandeld.
Sebazzz schreef op zondag 31 mei 2009 @ 09:26:
Maar hoe doe ik het dan met eventuele statements in het using block, ik kan moeilijk om iedere statement een try-catch zetten, iets verteld mij dat dat anders kan.
In een try kan meer dan 1 statement... En je kunt verschillende statements "samenvoegen" tot 1 "atomaire actie" in een sub/functie voor de overzichtelijkheid. Ik zie het probleem niet zo?

[ Voor 22% gewijzigd door RobIII op 31-05-2009 10:42 ]

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!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Sebazzz schreef op zondag 31 mei 2009 @ 09:26:
Maar hoe doe ik het dan met eventuele statements in het using block, ik kan moeilijk om iedere statement een try-catch zetten, iets verteld mij dat dat anders kan.
Het using statement gebruik je om je non-managed resources vrij te geven tijdens een exceptie. Je houdt op dat moment dus enkel nog standaard exception handling over.

Zoals RobIII zegt kun je meerdere catch blokken hebben per try, maar je kan ook verkiezen om je excepties te wrappen in domein-specifieke excepties en ze verder te throwen:
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
O o = ...
using (MyResource r = new MyResource())
{
  try
  {
    r.DoSomething();
    r.DoSomethingElse();
    r.CanThrowexception();
    o.X();
    r.Accept(o);
  }
  catch (FirstException fe)
  {
     throw new ResourceException("Could not tell peer what to do", fe);
  }
  catch (SecondException se)
  {
     throw new ResourceException("Resource did not accept data", se);
  }
  catch (exception e)
  {
     throw new ResourceException("An unknown error occurred.", e);
  }
}

[ Voor 4% gewijzigd door H!GHGuY op 31-05-2009 18:35 ]

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 06:48
RobIII schreef op zondag 31 mei 2009 @ 10:41:
[...]

In een try kan meer dan 1 statement... En je kunt verschillende statements "samenvoegen" tot 1 "atomaire actie" in een sub/functie voor de overzichtelijkheid. Ik zie het probleem niet zo?
Het probleem is, dat ik een onderbuikgevoel heb dat het niet netjes zo is, om zo'n 'groot' try-catch blok te hebben. Maar blijkbaar is er niets mis mee als ik jullie mag geloven :P

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Sebazzz schreef op zondag 31 mei 2009 @ 18:41:
[...]
Het probleem is, dat ik een onderbuikgevoel heb dat het niet netjes zo is, om zo'n 'groot' try-catch blok te hebben. Maar blijkbaar is er niets mis mee als ik jullie mag geloven :P
Er is niks mis met een groot try-catch block, sterker nog afhankelijk van de opbouw van je code kan het zelfs beter zijn om een groter try..catch te nemen. Het is over het algemeen juist zeer fout om een heel klein blok te nemen (een statement). Zoals wel vaker geldt het adagium 'Zo groot als nodig, en niet groter; zo klein als mogelijk, maar niet kleiner'.
Er is ook niks mis mee om bepaalde exceptions gewoon door te laten gaan of opnieuw op te gooien als dat op het juiste abstractieniveau is voor jouw API, of wrappen in een exception die meer op het abstractieniveau van jouw API is. Alleen in gevallen waarin je de foutconditie kunt wegnemen of zeker weet dat het een 'verwachte' exception is moet je de exception (na afhandeling) inslikken.
Pagina: 1