Page 3 of 3 FirstFirst 1 2 3
Results 31 to 40 of 40

Thread: Gebruik van Onvalidate

  1. #31
    Silly member NGLN's Avatar
    Join Date
    Aug 2004
    Location
    Werkendam
    Posts
    5,133
    John, de exceptions die jij waarschijnlijk bedoelt zijn de exceptions die niet zijn afgevangen, niet afgehandeld, en dus "doorbubbelen" naar boven totdat het Delphi framework hen zelf ook niet meer niet zinnig weet af te handelen en dus wel genoodzaakt is om een dergelijk dialoogvenster te tonen met de melding. Zo'n "automatisch" standaard foutmelding-venster dient voor alle duidelijkheid dus wél altijd voorkomen te worden, al is het alleen al omdat de foutmelding in de verkeerde taal is. Dat kan bijvoorbeeld door een event handler voor Application.OnException te schrijven, daarin de foutmelding te vertalen en/of beslissen of je hem op een willekeurige manier aan de gebruiker wilt laten zien, of je hem in de code afhandeld, of dat je hem negeert.

    Je kan ook er voor kiezen om exceptions niet centraal op te vangen, maar daar waar ze (kunnen) optreden.

    Delphi Code:
    1. procedure TForm1.OKButtonClick(Sender: TObject);
    2. begin
    3.   try
    4.     SaveData;
    5.   except
    6.     on E: EMyDataException do
    7.       ShowMessage(E.Message)
    8.     else
    9.       raise;
    10.   end;
    11. end;
    Hierin filter je dan op het type foutmelding dat je verwacht. Foutmeldingen die je niet verwacht raise je opnieuw zodat ze weer naar boven komen in de centrale foutafhandeling.
    Last edited by NGLN; 18-Jan-13 at 14:53.
    (Sender as TNLDUser).Signature := 'Groeten van Albert';

  2. #32
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Dat snap ik wel Albert.
    Misschien kijk ik helemaal in de verkeerde hoek. Honderdduizend keer wordt verteld dat je als je met data werkt, daar dat allemaal moet gebeuren via een aparte class of in een datamodule; dus buiten de Form om. Het gebruik van exceptions zorgt ervoor dat je een foutmelding kan tonen als er een fout wordt gecreëerd. Maar dan ga je toch een dialog openen met Showmessage of iets ergers.

    Een voorbeeld:
    delphi Code:
    1. procedure TDMArt.ArtikelenartikelValidate(Sender: TField);
    2. begin
    3.   if length(Sender.AsString) < 12 then
    4.     Showmessage('Artikelcode tekort');
    5. end;
    Deze procedure staat in een datamodule. Als het artikelcode te klein is, komt er een melding. Maar die melding toont een dialog, wat niet in een datamodule hoort. Sterker nog; je moet dialog.pas in je uses van je datamodule toevoegen, anders gaat deze niet eens werken. Als ik dezelfde dataset gebruikt, kan ik die validatie gebruiken.
    Maar als ik i.p.v. een Showmessage() het invoerveld wilt voorzien van een kleur of iets dergelijks, dan zal ik toch een event moeten afvangen om deze te laten retourneren naar de Form; dus de GUI.

    Nogmaals. Misschien denk ik wel veeeeeeeel te moeilijk.

  3. #33
    Silly member NGLN's Avatar
    Join Date
    Aug 2004
    Location
    Werkendam
    Posts
    5,133
    • De oplossing voor events, uitgaande van deze post:
      Delphi Code:
      1. procedure TDMArt.ArtikelenartikelValidate(Sender: TField);
      2. begin
      3.   if Length(Sender.AsString) < 12 then
      4.     ValidateError(Sender, 'Artikelcode te kort');
      5. end;
    • De oplossing voor exceptions:

      Delphi Code:
      1. procedure TDMArt.ArtikelenartikelValidate(Sender: TField);
      2. begin
      3.   if Length(Sender.AsString) < 12 then
      4.     raise EMyDataException.Create('Artikelcode te kort');
      5. end;
    (Sender as TNLDUser).Signature := 'Groeten van Albert';

  4. #34
    En in het laatste geval vang je die EMyDataException af in je exceptionhandler en toon je in het geval van EMyDataException een melding. Of je die melding met een showmessage, een label, een tooltip wilt doen is helemaal aan jou.

    Misschien heeft EMyDataException wel een property waarmee je het juiste veld kunt afvragen. Aan de hand daarvan kun je dan weer de betreffende control focus geven.
    Marcel

  5. #35
    Silly member NGLN's Avatar
    Join Date
    Aug 2004
    Location
    Werkendam
    Posts
    5,133
    Afgelopen week had ik een leuke gedachtewisseling met mijn broer en dat begon ongeveer met: "Wel verdraaid, waarom gebruiken ze daar nou excepties i.p.v. events?" Ik begreep de onvrede niet helemaal, want hij is in tegenstelling tot mij wél een professioneel programmeur; waarom zou hij nou problemen hebben met excepties?

    Uiteraard moest ik meteen aan dit topic denken waarin de beargumentatie voor en tegen events en excepties ook al een beetje over-en-weer werden geslingerd, waarbij - met alle respect natuurlijk - de hobbyisten met events kwamen en de specialisten met exceptions.

    Wat ik me tijdens dit topic namelijk nog helemaal niet had gerealiseerd en waar mijn broer mee aankwam: exceptions moet je afvangen, events mag je naar luisteren. Dat is nogal een verschil natuurlijk. Helemaal als de throwing code aan ontwikkeling onderhevig is en de calling code dat in mindere mate is. Nu ging zijn specifieke situatie helemaal niet over data-validatie, en dan kan ik me voorstellen dat er situaties zijn waarbij het je niet uitmaakt of er ergens iets fout gaat; dat je alleen maar geïnteresseerd bent in een aantal van alle mogelijke fouten die kunnen optreden.

    Dit alles zomaar ter info natuurlijk; als aanvullend argument, zowel v????r als tégen events. Het ligt er maar aan wat je als programmeur wel of niet wilt afdwingen. Wil je dat de gebruiker van jouw code (ook als je dat zelf bent) álle mogelijke fouten moet af/behandelen, dan zijn excepties daarvoor de aangewezen manier.
    Last edited by NGLN; 27-Feb-13 at 23:38.
    (Sender as TNLDUser).Signature := 'Groeten van Albert';

  6. #36
    Jup, dat is een belangrijk verschil. Overigens ben ik een 'beroeps', en ben ik ook niet voor het te pas en te onpas gebruiken van exceptions. Een gevaar van Exception is, dat je ze als control flow statements gaat gebruiken, ofwel, in plaats van ifjes die true of false teruggeven. Ergens aan het eind staat dan een Except-blok dat niets doet, behalve voorkomen dat de exception doorbubbelt naar het framework.

    Ik gebruik exceptions zelf juist voor dingen waarvan ik wil dat ze bij het framework uitkomen. Het zijn namelijk fouten. Exceptions zie ik als onderbreking van het huidige proces. En daarmee bedoel ik natuurlijk niet de draaiende applicatie als geheel, maar de actie die op dat moment uitgevoerd wordt.

    Normaliter staat je applicatie te wachten. Op een geven moment druk je op een knop, toon je een schermpje, en staat de applicatie weer te wachten. Na het invullen van wat gegevens druk je weer op de knop, en moet de applicatie wat gaan opslaan. Het proces dat getriggerd wordt door die knop, dat zie ik als een enkel, atomair proces dat helemaal kan lukken, of helemaal kan mislukken. Het lukt op het moment dat alles netjes weggeschreven is, en het mislukt op het moment dat bijvoorbeeld de databaseverbinding wegvalt, of er de tekst 'koe' is ingevuld in een integer-veld.

    Als je eenmaal op dat punt bent, dan wil ik een exception geven om die huidige actie helemaal af te breken.

    Het leuke is misschien wel dat ik ook bijna geen try..except blokken gebruik. Ik gebruik try..finally om dingen af te vangen, en try..except alleen om dingen op te ruimen die alleen opgeruimd moeten worden bij een fout. Een except-blok met een ShowMessage erin heb ik niet, want die message komt uit het framework. Als ik die exception wil vertalen naar een nettere melding, dan gebeurt dat centraal, in Application.OnException.

    Events zijn ook prima dingen, en ik maak er graag gebruik van, maar het zijn inderdaad optionele implementaties. Je kunt een OnClick event aan een button hangen, maar het hoeft niet. Het hoeft alleen als je wilt dat de button ook wat doet.
    Beter voorbeeld: Je kunt een handler aan het OnShow event van een form koppelen, maar dat doe je alleen als je wat speciale handelingen wilt uitvoeren voordat het form getoond wordt. Die implementatie is optioneel en het event-model is daar prima geschikt voor, al dient het een ander doel.

    Een aanverwante thread, Oneindige lus in OnValidateschreef ik over het verschil tussen GUI hulpmiddelen en blokkeren van onjuiste invoer, en ik denk dat dat hier ook aan de orde is. M.b.v. events kun je de gebruiker op een vriendelijke manier helpen. Met behulp van exceptions voorkom je troep in je database.

    Ik ben van mening (en ik weet zeker dat ik gelijk heb ) dat je de exception handling in ieder geval moet hebben vanuit een technisch perspectief. Je wilt koste wat het kost voorkomen dat je data gevaar loopt, en evenzeer dat er stilzwijgend iets wordt geannuleerd zonder het te melden.
    Daarbij vind ik als UX designer dat je ook de juiste GUI hulpmiddelen moet aanbieden om de kans zo klein mogelijk te maken dat je gebruiker die exception krijgt. Dat doe je door met o.a. het OnValidate event te controleren of een waarde geldig is, vinkjes, kruisjes of kleurtjes te tonen als invoer wel of niet goed is, een datepicker te tonen i.p.v. een editbox, en de OK-knop uit te schakelen zolang nog niet alles OK is.

    Als je alles altijd helemaal dicht zet, dan zou je kunnen redeneren dat je die exceptions niet meer nodig hebt, maar dat is niet waar. Het dichttimmeren van een GUI is veel lastiger, en je bent in sommige gevallen afhankelijk van de client. Een web-interface kan wellicht ineens zonder Javascript werken, waardoor de knop niet wordt uitgeschakeld, maar zelfs in Windows kun je controls beïnvloeden van buitenaf door messages te sturen.
    Nog afgezien van dat soort fraude, is de GUI vaak veel ingewikkelder.
    Dus mijn afvies: Begin met een goede foutafhandeling. Zorg dat je bij problemen op kritieke punten een exception gooit als dat nog niet vanzelf gebeurt. Zorg dat het proces ook afbreekbaar is en dat de finally-blokken op de juiste plek staan om vrij te geven wat er vrijgegeven moet worden.

    Als dat werkt, dan ga je het gebruikersvriendelijker maken. Stap één is het inpakken van die exception in een iets leesbaardere melding. Dat kan dus in de centrale Application.OnException handler. Dat is een goedkope aanpassing, al lever hij niet zoveel op. Het invoeren zelf wordt er namelijk niet makkelijker door, en het is maar de vraag hoeveel leesbaarder je een melding kunt maken.
    De volgende stap is dus het dichttimmeren van de GUI, zodat de kans op domme fouten en verkeerde invoer kleiner is.

    PS: Albert, is die broer van jou ook lid van NLDelphi?
    1+1=b

  7. #37
    Silly member NGLN's Avatar
    Join Date
    Aug 2004
    Location
    Werkendam
    Posts
    5,133
    Nee, hij programmeert in Java. Vorige week heb ik wel geprobeerd om hem "aan de Delphi" te krijgen , maar dat is me nog niet helemaal gelukt...

    Ik gebruik try..finally om dingen af te vangen,
    Daar bedoel je in ieder geval niet mee dat je in de finally een rood uitroepteken achter verkeerde invoer plaatst. Ook niet een rollback. Wat doe jij dan wel in de finally? Voorbeeldje?
    (Sender as TNLDUser).Signature := 'Groeten van Albert';

  8. #38
    Leuk dat je rollback zegt, want dat is toevallig een voorbeeld waar je wel try..except gebruikt, zelfs als je de exception zelf daar niet wilt laten eindigen:

    Delphi Code:
    1. BeginTransaction;
    2. try
    3.   // Doe Opslaan
    4.  
    5.   Commit;
    6. except
    7.   Rollback;
    8.   raise; // Exception zelf gewoon doorsturen.
    9. end;
    Maar in die finally doe ik niets anders dan opruimen. 'Afvangen' was misschien ook niet het beste woord. Natuurlijk vang ik de exception af, maar alleen om de boel op te kunnen ruimen en 'm daarna door te laten wandelen naar het punt waarop de VCL me een melding met een rood kruis geeft.
    Maar zo komen we meer in het semantische deel van de discussie.
    1+1=b

  9. #39
    Delphi & OO in Vlaanderen SamWitse's Avatar
    Join Date
    Sep 2007
    Location
    Brussel
    Posts
    833
    Een exception is voor mij iets als 'Hier loopt het fout, en ik zou niet weten hoe ik (=het component, de klasse) er toch nog iets zinnigs van moet maken".
    Stel dat je klasse verantwoordelijk is voor de update van een integer-veld, en de waarde 'koe' binnen krijgt. Ofwel zegt die klasse 'Met een koe kan ik niets, ik hou er mee op', en gooit een exceptie. Ofwel zegt die klasse 'Een koe? Da's vreemd? Daar maak ik stiekum een 0 van'. Ofwel zegt die klasse 'Een koe? Daar kan ik niks mee, ik vaag effe aan mijn opdrachtgever de GUI wat ik daarmee moet. Zegt die niks, dan maak ik er een 0 van'
    Optie 1: een exception
    Optie 2: een stilzwijgende vervanging van een aangeleverde waarde
    Optie 3: een event

    Je kunt ook een optie maken van 1 en 3 samen: als de GUI met een foutmelding in een event nog niks zinnigs aanvangt, dan zegt de klasse: "Sorry, ik heb je gevraagd wat ik er mee moest doen en je antwoordt niet, maar hier kan ik echt niets mee; ik stop er mee."

    Misschien mis ik iets in Delphi, maar ik heb helemaal geen vat op waar exceptions mogelijks kunnen opgegooid kunnen worden, en wat die exceptions dan wel kunnen zijn. Kun je dat ergens zien? Met andere woorden: moet ik rond TGolezKlasse.DoeIetsMoeilijks een try except bouwen, en zo ja waarom? Hoe kan ik dat achterhalen?
    Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration.

    Sam Witse.
    Delphi & OO in Vlaanderen

  10. #40
    Je kunt inderdaad ovearl try/excepts omheen zetten, maar in veel projecten is één plaats voldoende.

    Veel van mijn projecten zijn "ontvang data van de buitenwereld en doe daar iet mee" services. Daar is één try / except eigenlijk wel voldoende. Je leest een XML document in en dat lukt of geeft een exceptie. In het geval van een exceptie kun je nog kijken of het iets tijdelijks is. Is dat het geval laten we het bestand lekker staan en gaan we het over X minuten nog eens proberen. Gaat het dan weer fout dan is er blijkbar iets meer aan de hand en gaan er alarmen naar buiten. In mijn geval: een mail naar mezelf en iemand bij de klant zodat het probleem wordt opgepakt. Is het een fout in het bestand dan gaat dat zichzelf niet oplossen. Het bestand wordt in een errormap gezet en er wordt weer een mail gestuurd. Kortom: één try, doe je ding, except, los het op of trek aan de bel.

    In het geval van UI projecten heb ik een aantal soorten excepties. Ook hier is maar één exception handler die ze afhandelt. Als eerst wordt er gekeken of het een TDeGebruikerSlaatEenVerkeerdeWaardeOp exceptie is. In dat geval is een simpele melding voldoende, eventueel met een kleurtje bij de label van de control en misschien geven we ook de control wel focus. Als het een serieuzere melding is kun je ook daar weer kijken of het iets tijdelijks is. In het geval van "server niet gevonden" zou je nog een melding kunnen geven aan de gebruiker met de tekst dat hij maar even koffie moet gaan drinken en het dan nog eens moet proberen. In serieuzere gevallen geef je een melding aan de gebruiker dat er iets serieus mis is en stuur je de melding met een callstack, informatie van de omgeving en een schermafdruk naar jezelf.

    Dat is het eigenlijk wel, er zijn maar weinig situaties waar ik onderweg nog try / except structuren nodig heb. Die uitzonderingen zijn dan vooral in de "ruim je rommel op" hoek. Als ik een bestand tijdelijk in een map heb opgeslagen is een try / except wel zinvol, maar dan alleen in de vorm try / except / ruim het bestand op / raise. De algemene exceptionhandler is ervoor gemaakt om de exceptie af te handelen, dat moet ik dus niet lokaal gaan oplossen.

    Wat zou je in Delphi nog meer voor structuren willen zien om dat makkelijker te maken?
    Marcel

Page 3 of 3 FirstFirst 1 2 3

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •