Encapsulation is the first pillar of Object Oriented Programming (OOP), yet most code that I see does not implement encapsulation correctly or not all. Like I say in many of my conference sessions "If you do not implement encapsulation, you aren't doing OOP!" I also say "Bad data in, bad data out!".
Several years ago, Microsoft Labs came out with Code Contracts which made encapsulation easy so I implemented in all my projects and even did conference sessions about it. Unfortunately, the future of Code Contracts looks dim and it does not work in .NET Core or .NET Standard. Since I moved some of the code I’ve been writing since .NET came out in my open source project dotNetTips.Utility to .NET Standard, I needed a way to mimic the encapsulation features of Code Contracts.
Introducing the dotNetTips.Utility OOP Namespace
I created a new namespace in my open source project called OOP in both my .NET Portable project and .NET Standard project. The first class in this namespace is named Encapsulation. In this class, you will find overloaded methods called TryValidateParam, designed to make encapsulation easier. Here is the main method in this class.
- public static void TryValidateParam < TException > (bool condition, string paramName = "", string message = "")
- where TException: ArgumentException, new() {
-
- var t = typeof(TException);
- if (t.Name == nameof(Exception)) {
- throw new InvalidCastException(Resources.CannotBeOfTypeException, nameof(TException)));
- }
- var defaultMessage = Resources.ParameterIsInvalid;
- if (string.IsNullOrEmpty(message) == false) {
- defaultMessage = message;
- }
- if (condition == false) {
- var ex = Activator.CreateInstance(typeof(TException), paramName, defaultMessage).As < TException > ();
- throw ex;
- }
- }
There are a few things I would like to point out in this method. First, it prevents users from throwing the type Exception, which you should never do since it is not descriptive enough. The only Exception type that should be thrown when checking parameters is one derived from ArgumentException. The exceptions included in the .NET Framework are:
- ArgumentNullException
- ArgumentOutOfRangeException
If one of these types does not meet your needs, then create your own inheriting ArgumentException. I did this in dotNetTips.Utility with the ArgumentInvalidException and ArgumentReadOnlyException.
The overloaded methods in this class makes it easy to check strings, collections, enums, GUID’s and more.
Example
Here is an example on how to use TryValidateParam (also from dotNetTips.Utility).
- public static DateTime GetLastDay(this DateTime input, DayOfWeek dayOfWeek) {
- Encapsulation.TryValidateParam(dayOfWeek, nameof(dayOfWeek));
- var daysToSubtract = input.DayOfWeek > dayOfWeek ? input.DayOfWeek - dayOfWeek : (7 - (int) dayOfWeek) + (int) input.DayOfWeek;
- return input.AddDays(daysToSubtract * -1);
- }
I hope you will implement this in your code too. To download from GitHub, click here. If you have any comments about this project, please add one on the GitHub site.