There is an inherited class:

public class Division : BinaryOperation { protected override decimal Calculate(decimal a, decimal b) { return a / b; } public override string Name { get { return "Π”Π΅Π»Π΅Π½ΠΈΠ΅"; } } } 

How inside it beautifully and logically handle the situation of division by zero? If you wrap in try-catch, what to write in catch? Suppose I do not know what controls will be on the form, and in general, will it be used in WinForms or WPF or something else to display the text Exception somewhere. Perhaps there are some other good options besides try-catch?

  • one
    it’s better not to process it inside - Grundy
  • one
    you do not have to handle it, this is the task of the calling code, as well as checking the parameters passed to the operation before the call. - rdorn

2 answers 2

The difficulty with "elegant" exception handling is that it depends heavily on the context.

For example, in one application, you need to select the UI control and ask the user to enter a valid value. In another application (if it is a server), you need to throw an exception that must cross the application boundary in one way or another. And in the third application, checking the arguments takes place at a higher level and passing 0 to parameter b is a bug and should cause the application to crash.

All this leads to the following features:

  1. Add a precondition to the Calculate method that b != 0 : Contract.Requires(b != 0) . In this case, we shift the responsibility for code validation to the caller. We say that 0 is an invalid value, and we ask the client not to touch us in this case.

  2. Do nothing and forward a DivideByZeroException . Another alternative is to document the Calculate method and "say" that this exception might flow from it.

In this case, we again shift the responsibility to the calling code, which knows better what to do with it. Now the client can issue a message, send the desired response to the client, or convert this exception to some other one.

  1. Add a new level of indirection. Also, you can add a special type of exception, for example, CalculationException or OperationException . In this case, a new type of exception will describe a family of errors that can occur when working with an abstract operation.

This solution is more extensible, since new heirs may throw new and new types of exceptions, and a specific type of exception may contain more specific information:

 public abstract class OperationException { } public class DivideByZeroOperationException : OperationException {} public class Division : BinaryOperation { protected override decimal Calculate(decimal a, decimal b) { if (b == 0) {throw new DivideByZeroOperationException();} return a / b; } } 

The client can now decide whether to handle the base exception or more specific one.

  1. Another alternative is to go back to smart return codes and get away from the exceptions.

Example:

 public enum Error { DivideByZero, YetAnotherError } // Π­Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠΉ сСбС 'Either' Ρ‚ΠΈΠΏ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ Π»ΠΈΠ±ΠΎ ΠΎΡˆΠΈΠ±ΠΊΡƒ (ΠΊΠΎΠ΄ ΠΈ, // Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, сообщСниС), Π»ΠΈΠ±ΠΎ Π²Π°Π»ΠΈΠ΄Π½Ρ‹ΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ public class OperationResult { public decimal? Result {get;} public Error? Error {get;} public static OperationResult Success(decimal result) { } public static OperationResult Failure(Error error) { // ΠœΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ стоит Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ сообщСниС ΠΈΠ»ΠΈ Π΄Ρ€ΡƒΠ³ΡƒΡŽ ΠΊΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚Π½ΡƒΡŽ ΠΈΠ½Ρ„ΠΎΠΌΡ€Π°Ρ†ΠΈΡŽ } } public class Division : BinaryOperation { protected override OperationResult Calculate(decimal a, decimal b) { if (b == 0) {return OperationResult.Error(Error.DivideByZero);} return a / b; } } 

This is a more "functional" approach, while the previous ones are more canonical in OO languages, such as C #.

The main conclusion: there is no imputed way to fully handle the exception inside the Calculate method . Error information must be passed to the calling code, since only at a higher level there is enough information (context) to handle this problem in a complete way.

    Apparently, this is some kind of computer of a general form. In this calculator there should be a general system of errors, which should be used by this particular class of division operation.

    The use of exceptions is most likely unacceptable for many reasons. In particular, the division by zero in this area is, firstly, a normal situation, and secondly, it does not mean that you need to destroy something on the occasion of an β€œerror” and remove someone from the stack.

    Most likely, the general computing error handling system should explicitly provide for an error or even a list (hierarchical) of errors as a possible result of any operation. There are a lot of design options for such a scheme - you can start with hints from the answer Sergey Teplyakov.

    And do not forget that in general-type calculators, division by zero is not always an error, and sometimes infinity, plus positive or negative, or even NaN!