I was also looking for a solution on how to catch exceptions caused by contract terms. It is always a good idea to explicitly throw exceptions that may occur. Wether you want to catch them so that your code does not stop with a big hit, it depends on what data is checked. I also use contracts to validate user input. With the preconditions of the contract, you can force input of user input in accordance with certain requirements (for example, not an empty or empty string). Secondly, you can use contracts to verify your own internal code (especially calculations) and ensure not only the input of parameters, but also the result of calculations.
You can catch exceptions to the terms of the contract ; just put the calling code inside the try-catch block and explicitly catch the type of exceptions (s) that will cause your conditions (states). I would only do this with user input validation. Since , when the conditions of the contract are configured not only to check the parameters, but also for the logic of the main code, output an error ; something may be wrong with your code logic, not with parameters. In this case, it is better to completely stop the program . But if you want your program to end in a more controlled way, you can catch them. Then you need to check whether the program can continue or not .
And I found out that you can also check for null references to events (at least created by yourself). I used it in my own code example, which also catches the error caused by the contract. You need to pass the event or object that triggers the event as an additional parameter to access the event. The following code is part of what I have in one of my classes:
public delegate void Transactie(Rekening rekening);//signature for events public Transactie RekeningUittreksel; public Transactie NegatiefSaldo; public void Storten(decimal bedrag,Transactie actie) { Contract.Requires<NullReferenceException>(actie!=null,"\n\nNo event listeners have been added yet!\n\n"); VorigSaldo = Saldo; Saldo += bedrag; RekeningUittreksel(this); } public void Afhalen(decimal bedrag,Transactie actie,Transactie actie2) { Contract.Requires<NullReferenceException>(actie!=null,"\n\nNo event listeners have been added yet!\n\n"); Contract.Requires<NullReferenceException>(actie2 != null, "\n\nNo event listeners have been added yet!\n\n"); VorigSaldo = Saldo; if (bedrag <= Saldo) { Saldo -= bedrag; RekeningUittreksel(this); } else { NegatiefSaldo(this); } }
Next is part of the main program method. I commented out the lines where I add event listeners, so the contract rules described above will throw an exception using noreference. Here's how to catch them without stopping with a big hit:
//mijnZichtrekening.RekeningUittreksel += pietjePek.ToonUittreksel; //mijnZichtrekening.NegatiefSaldo += pietjePek.ToonNegatief; try { mijnZichtrekening.Storten(50m, mijnZichtrekening.RekeningUittreksel); } catch (NullReferenceException ex) { Console.WriteLine(ex); } try { mijnZichtrekening.Afhalen(100m, mijnZichtrekening.RekeningUittreksel, mijnZichtrekening.NegatiefSaldo); } catch(NullReferenceException ex) { Console.WriteLine(ex); }
I rewrote some code a bit to check for null event references using the new .NET 4.5 contract abbreviations:
public void Afhalen(decimal bedrag) { NegatiefSaldoHasListeners(this.RekeningUittreksel, this.NegatiefSaldo);//calls the contract abbreviator with delegate type parameters to check for Nullreference VorigSaldo = Saldo; if (bedrag <= Saldo) { Saldo -= bedrag; RekeningUittreksel(this); } else { NegatiefSaldo(this); } } public void Storten(decimal bedrag) { UittrekselHasListeners(this.RekeningUittreksel);//calls the contract abbreviator with a delegate type (event) parameter to check for Nullreference VorigSaldo = Saldo; Saldo += bedrag; RekeningUittreksel(this); } public virtual void Afbeelden() { Console.WriteLine("Rekeningnr: {0:0000 0000 0000 0000}",Nummer); Console.WriteLine("Saldo: {0}",Saldo); Console.WriteLine("Creatiedatum: {0:dd-MM-yyyy}",CreatieDatum); } [ContractAbbreviator] public void CheckArgs(string nummer, Klant eigenaar) { Contract.Requires<ArgumentException>(!String.IsNullOrWhiteSpace(nummer), "Geen nummer ingevuld!"); Contract.Requires<FormatException>(nummer.Trim().Length == 16,"Ongeldig aantal tekens ingevoerd!"); Contract.Requires<ArgumentException>(!String.IsNullOrWhiteSpace(eigenaar.ToString()), "Eigenaar niet opgegeven!"); } [ContractAbbreviator] public void UittrekselHasListeners(Transactie actie) { Contract.Requires<NullReferenceException>(actie != null, "\n\nGeen event listener toegewezen!\n\n"); } [ContractAbbreviator] public void NegatiefSaldoHasListeners(Transactie actie,Transactie actie2) { Contract.Requires<NullReferenceException>(actie != null, "\n\nGeen event listener toegewezen!\n\n"); Contract.Requires<NullReferenceException>(actie2 != null, "\n\nGeen event listener toegewezen!\n\n"); }