Lazov
Lazov

Reputation: 1476

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.

Upvotes: 3

Views: 1978

Answers (2)

Fabio
Fabio

Reputation: 32445

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();

Upvotes: 4

Gilad Green
Gilad Green

Reputation: 37299

I do agree with what others say here that having your BL enforced by exceptions is not a good practice. Instead of the exception you can return a "ResultObject" that contains a success status + details and the valid return data.

But if you do choose to do so then customize your custom exception to include more than just a default constructor. They are just like any other class. Something like:

public class MyCustomException : Exception
{
   //This is like you have now
   public MyCustomException() { }

   //This is if you want to have different messages
   public MyCustomException(string message)  : base(message{ }

   //This is if you want to have different data to add (don't use object but a custom type
   public MyCustomException(object yourObject)
   {
      YourObject = yourObject;
   }

   public object YourObject { get; set; }
}

In your scenario then probably something like:

public class EmployeeException : Exception { ... }
//Add what you need from the example above

//Then when needed:
new EmployeeException("some text for this error");
new EmployeeException("some other text for this error");

//Or when with a proper object to describe more details:
new EmployeeException(new NotEnoughHours { ... });

Upvotes: 1

Related Questions