Como um programador experiente, você precisa lidar com ocorrências NullReferenceException todos os dias. Certo? Eu defendo que este é um problema de design. Por favor, considere o código que segue:
public interface IEmployeeRepository
{
Employee GeyById(string id);
}
class EmployeeRepository : IEmployeeRepository
{
public Employee GetById(string id)
=> new DbContext().Find(id);
}
Qual deveria ser o resultado da execução de GetById? Uma instância de Employee, certo? Infelizmente, este não é o caso sempre. Se não há registro com o id especificado, o resutaldo seria null. Talvez você esteja conformado com isso. Eu não!
O fato é que o código não é totalmente claro sobre qual deveria ser o resultado esperado para a execução desse método. Como programador experiente, algumas vezes você vai verificar o resultado do método, mas as vezes não…
Minha proposta seria começar a usar um container indicando que, as vezes, o resultado seria “sem resultado”.
public interface IEmployeeRepository
{
Option<Employee> GeyById(string id);
}
class EmployeeRepository : IEmployeeRepository
{
public Option<Employee>; GeyById(string id)
=>; new DbContext().Find(id);
}
Agora o código é bem mais claro. Não acha?
Sobre a implementação de Option
O tipo Option é apenas uma struct que provê algumas conversões implicitas e algumas operações funcionais básicas.
A coisa mais interessante sobre essa abordagem é que os programadores consumindo EmployeeRepository do exemplo anterior não teriam mais acesso direto a (possível) instância de employee. O único meio para ter acesso seria através do container.
public IActionResult Get(string id) => _repository.GetById(id)
.Match<IActionResult>(
some: employee => Ok(employee),
none: () => NotFound()
);
NullReferenceExcption se foi!