Search code examples
c#exceptioncustom-exceptions

Return information with Custom Exceptions C#


I have the following problem:

  1. I have a service method:

    public bool EmployeeCanReiceivePayment(int employeeId)
    {
       ...
    
       int workingHours = this.GetEmployeeWorkingHours(employeeId);
    
       if(workingHours < N)
       {
         throw new EmployeeCannotReceivePaymentException();
       }
    
       return true;
    }
    
     public int GetEmployeeWorkingHours(int employeeId)
    {
      //returns the number of working hours of the employee for the last month
    }
    

GetEmployeeWorkingHours is just one of the methods to check if the employee can receive salary (so there can be another reason for the employer not to pay). For each of this reasons I want to throw an exception with the appropriate information: Number of required working hours, number of the actual working hours etc..

The question is:

Is there a way to return an object or additional information with my Custom exception. And by additional information I mean an object or just several paramenters.


Solution

  • Avoid using exceptions for control flow

    This is rule of .NET Framework usage

    DA0007: Avoid using exceptions for control flow

    The use of exception handler as part of the regular program execution logic can be expensive and should be avoided. In most cases, exceptions should be used only for circumstances that occur infrequently and are not expected..

    Instead of throwing exception create a class which will contain all needed information.

    public class PaymentValidation
    {
        public bool IsValid { get; set;}
    
        public YourType SomeAdditionalInformation { get; set;}
    }
    
    public PaymentValidation EmployeeCanReiceivePayment(int employeeId)
    {
        int workingHours = this.GetEmployeeWorkingHours(employeeId);
    
        var validationResult = new PaymentValidation();
        validationResult.IsValid = true;
    
        if(workingHours < N)
        {
            validationResult.IsValid = false;
        }
    
        return validationResult;
    }
    

    Returning own type will give more possibilities for further changes.

    For example create an interface which represent returned type. And create own implementation for every case you have

    public interface IPayment
    {
        void Pay();
    }
    

    Implement interfaces for every case

    public class NotEnoughWorkingHoursPayment : IPayment
    {
        public void Pay()
        {
            //Do nothing or log failed payment or inform user about it
        }
    }
    
    public class SuccesfullPayment : IPayment
    {
        public void Pay()
        {
            //Execute payment
        }
    }
    
    
    public class PaymentService
    {
        public IPayment ValidatePayment()
        {
            const int MIN_WORKING_HOURS = 40;
            int workingHours = this.GetEmployeeWorkingHours(employeeId);
    
            if(workingHourse < MIN_WORKING_HOURS)
            {
                return New NotEnoughWorkingHoursPayment();
            }
    
            return new SuccesfullPayment();
        }
    }
    

    Then using will be very easy and understandable

    IPayment payment = paymentService.ValidatePayment();
    
    payment.Pay();