A guard clause is a software pattern that simplifies complex functions by “failing fast”, checking for invalid inputs up front and immediately failing if any are found.
Guard clauses should be used under exceptional circumstances, meaning that if an application gets to a point where under normal circumstances the specific scenario should not have happened or been possible then an exception should be raised.
Guard Clauses are not appropriate for things such as user input validation as invalid inputs are expected and thus not exceptional. See, this blog post for further reading on Guard Clauses and Exceptions or Validation.
Let’s take for example creating an invitation list:
- The invitation list is comprised of invitees
- All invitees must have an email address to send an invitation to
- Other information such as first name / last name is optional
Given the requirements above, our exceptional circumstance that we want to make sure we guard against is if some part of the application tries to create an Invitee without an Email.
The Invitee object may look something like this:
public class Invitee
{
public string Email { get; private set; }
public string? FirstName { get; private set; }
public string? LastName { get; private set; }
public Invitee(string email, string? firstName, string? lastName)
{
Email = email;
FirstName = firstName;
LastName = lastName;
}
}
We want to prevent creating an Invitee without an Email. So what are our options to prevent this?
- Wrap the code in a try/catch block
- Put if/else statements around the specific fields and throw exceptions or take the appropriate action in a failure scenario
Both of the options above are a bit clunky and verbose and only get worse as you add in additional properties that need to be guarded against and potentially take different actions upon failure.
Enter Ardalis.GuardClauses
The solution for me is to use guard clauses and to specifically leverage the Ardalis.GuardClauses library. Now, instead of using a try/catch or if/else statements I can use a single line to guard against the Email being null.
public class Invitee
{
public string Email { get; private set; }
public string? FirstName { get; private set; }
public string? LastName { get; private set; }
public Invitee(string email, string? firstName, string? lastName)
{
Email = Guard.Against.NullOrEmpty(email, nameof(Email));
FirstName = firstName;
LastName = lastName;
}
}
If the Email is null, now there will be a System.ArgumentNullException
thrown indicating that the Email cannot be null.
Guard Clauses, and this library, don’t only apply to properties on objects. For example, you can leverage guard clauses to ensure a service has all the required dependencies to do its job.
public class TestService
{
private IService1 Service1;
private IService2 Service2;
public TestService(IService1 service1, IService2 service2)
{
Service1 = Guard.Against.Null(service1, nameof(service1));
Service2 = Guard.Against.Null(service2, nameof(service2));
}
}
In the above code snippet, this service will immediately throw an exception if there is an issue with the dependency injection configuration that wires up Service1
and/or Service2
.
Now, you’re failing fast and the exceptions that are thrown contain sufficient information to determine where the issue is occurring. Its much more clear to receive an error indicating that service1
was null rather than an error at runtime with many nested inner exceptions.
Not only does this library have many supported guard clauses out of the box that will typically cover most scenarios you would come across but you can also extend it to create your own custom Guard Clauses.
In a future blog post, I’ll take us through how to extend this library and create our own custom guard clause.