You may have validating annotations that restrict the aceptable returned values. Here is an example in Java for Spring taken from baeldung.com but in C# you have a similar feature:
@NotNull @Size(min = 1) public List<@NotNull Customer> getAllCustomers() { return null; } If you use this approach you must consider that:
- You need a validation framework for your language, in this case C++C#
- Adding the annotation is just one part. Having the annotation validated and how this validation errors are handled are the important part. In the case of Spring it creates a proxy using dependency injection that would throw a Runtime ValidationException
- Some annotations may help your IDE to detect bugs at compile time. For example, if you use @NonNull the compiler can check that null is never returned. Other validations needs to be enforced at runtime
- Most validation frameworks allow you to create custom validations.
- It is very useful for processing input data where you may need to report more than one broken validation at the same time.
I do not recommend this approach when the valdiation is part of the business model. In this case the answer from Euphoric is better. The returned object will be a Value Object that will help you create a rich Domain Model. This object should have a meaningful name with the restrictions acording to the type of business you do. For example, here I can validate that dates are reasonables for our users:
public class YearOfBirth private final year; public YearOfBirth(int year){ this.year = year; if(year < 1880){ throw new IllegalArgumentException("Are you a vampire or what?"); } if( year > 2020){ throw new IllegalArgumentException("No time travelers allowed"); } } } The good part is that this kind of object can attract very small methods with simple and testeable logic. For example:
public String getGeneration(){ if( year < 1964){ return "Baby Boomers"; } if( year < 1980 ){ return "Generation X"; } if( year < 1996){ return "Millenials"; } // Etc... }