As an experienced .NET developer, you have to deal with NullReferenceException occurrences every day. Am I right? I firmly believe this is a design problem. Please, consider the following code sample:

public interface IEmployeeRepository
{
  Employee GeyById(string id);
}

class EmployeeRepository : IEmployeeRepository
{
  public Employee GetById(string id)
    => new DbContext().Find(id);
}

What should be the result of the GetById execution? An Employee instance, right? Unfortunately, this is not the case all the time. If there is no record with the specified id, the result would be null. Maybe you think that is ok, but I don’t think so.

The fact is the code is not entirely clear about what should be the expected result of the method execution. As an experienced developer, sometimes you will check the method result, but sometimes not…

My proposal would be to start using a container indicating that, at times, the result would be “no result.”

public interface IEmployeeRepository
{
  Option<Employee> GeyById(string id);
}

class EmployeeRepository : IEmployeeRepository
{
  public Option<Employee>; GeyById(string id)
    =>; new DbContext().Find(id);
}

Now, the code is clearer. Don’t you think?

What about the Option implementation

The Option Type is just a regular C# struct that provides implicit conversions and very basic functional operations.

The most interesting thing about this approach is that programmers consuming the EmployeeRepository from the previous example would not have direct access to the (possible) employee instance. The only way to get it would be thorugh the container.

public IActionResult Get(string id) => _repository.GetById(id)
  .Match<IActionResult>(
    some: employee => Ok(employee),
    none: () => NotFound()
  );

NullReferenceExcption is gone by design.

Nice, right? Option Type is available on my github.

Leave a Reply