Advertisement
Pipe
RSS
.NET Framework .NET C# VB.NET LINQ ASP.NET Web API REST SignalR Windows Forms WPF WCF RabbitMQ PHP SQL Server MySQL PostgreSQL MariaDB SQLite MongoDB ADO.NET ORM Entity Framework Dapper XML JSON HTML5 CSS3 Bootstrap JavaScript jQuery Angular React TypeScript NPM Blazor UI/UX Responsive Web Design Redis Elasticsearch GraphQL Grafana Agile Scrum Kanban Windows Server IIS PowerShell Active Directory TFS Azure Automation Software Reverse Engineering Performance Optimization Git Jira/Confluence CI/CD TeamCity SOLID KISS DRY YAGNI
Always will be ready notify the world about expectations as easy as possible: job change page

Never return NULL references from your functions

Created: Jul 11, 2021
Author: Sasha Mathews
Source: source
Views: 635

In C#, reference types can be assigned null values. This is something that developers will have to live with until they use classes to create software. Unfortunately, the folks at Microsoft cannot simply disallow null assignment to reference variables at compile time, because that would break the codebase of almost every project.

Returning Null is bad practice

What is actually wrong with returning a null reference from the method?

Let’s take a look at this simple method:

public Order GetOrder(int orderId)
{
    var order = _db.Orders.FirstOrDefault(u => u.OrderId == orderId);
    return order;
}

The FirstOrDefault method silently returns null if no order is found in the database.

There are a couple of problems here:

  • Callers of GetOrder method must implement null reference checking to avoid getting a NullReferenceException when accessing Order class members. But how is the caller supposed to know how to properly implement error handling? Should the caller throw an exception if it receives a null reference or return some error code?
  • When each caller implements the validation logic on its own, it will be duplicated and the chances are high that the logic will not be consistent across all callers. This is a violation of DRY principle.
  • Getting a nullvalue is an ambiguous for caller, because it doesn’t say whether the null is returned due to the bug or due to the fact that the order was not found in the database. Returning null is definitely not a domain-driven design approach.
  • Returning null is often a violation of the fail fast programming principle. The null can appear due to some issue in the application. The issue can even go to production if the developer has not implemented proper exception handling, which can help quickly detect the issue.

Developers can do several things to improve the situation, such as using a nullable reference types, throwing an exception, or using the null object design pattern.

Use Nullable reference types

If the developer really needs to return a null value from the method (in 99% of cases this is not necessary), the return type can be marked as a nullable reference type (the feature was introduced in C# 8.0).

public Order? GetOrder(int orderId)
{
    var order = _db.Orders.FirstOrDefault(u => u.OrderId == orderId);
    return order;
}

Marking a return type as nullable has two main benefits:

  • The method signature clearly states that it can return a null reference. This way, callers know for sure that they need to implement error handling just by looking at the method signature.
  • The compiler will emit a warning if the caller accesses members of the Order class without first checking for a null reference.

Fail fast by throwing an Exception

The fail fast principle is an important principle in software engineering. The idea is pretty simple — as soon as the application detects a problem (null reference), it should throw an exception.

Incorrect orderId can be caused by the following reasons:

  • The auto mapping library is not configured properly to map orderId values.
  • Some code accidentally assigned the wrong value to orderId variable before calling GetOrder method.
  • The frontend does not pass order IDs to the backend.

Each reason described is a bug in the application. Thus, according to the fail fast principle, as soon as the system detects that the orderId is not valid, it should throw an exception.

The easiest way to throw an exception for orders not found is to use the First method instead of FirstOrDefault in the implementation.

public Order GetOrder(int orderId)
{
    var order = _db.Orders.First(u => u.OrderId == orderId);
    return order;
}

But we have another problem: callers will get InvalidOperationException without any valuable information because this is a common .NET exception. The solution for that is to introduce a custom exception type which the developer should throw once the order was not found in the database.

public Order GetOrder(int orderId)
{
    var order = _db.Orders.FirstOrDefault(u => u.OrderId == orderId);
    
    if (order == null)
    {
        throw new OrderNotFoundException($"Order {orderId} was not found in the database.");
    }
    
    return order;
}

To summarize the benefits of the custom exceptions approach:

  • The chances of issues being discovered and fixed prior to deploying a production environment are much higher.
  • The caller will get detailed information about the problem, which will simplify the troubleshooting process.

Use Null object design pattern

Another way to avoid returning null is to use a Null object design pattern.

A null object is an object without behavior like a stub that a developer can return to the caller instead of returning null value.

public Order GetOrder(int orderId)
{
    var order = _db.Orders.FirstOrDefault(u => u.OrderId == orderId);
    
    if (order == null)
    {
        return new Order();
    }
    
    return order;
}

The caller doesn’t need to check the order for null value because a real but empty Order object is returned.

The null object pattern should be carefully considered as an alternative to throwing an exception. Using the pattern is contrary to the fail fast principle.

This pattern should be used only when callers would otherwise check the object for null in order to skip access to its members.

Conclusion

The conclusion is simple — never return null references from your methods.

Similar
Jun 8, 2023
Author: Juan Alberto España Garcia
At the end of this article you will understand what “^(?=.*[a-z])(?=.*[A-Z])(?=.*).*” meansIntroduction to C# Regex: why it’s a powerful tool for text manipulationBefore diving into the magical world of regular expressions, let’s get an idea of why using C# Regex...
Jan 10, 2023
Author: Shubhadeep Chattopadhyay
Exception Handling is one of the important topics in Software Development. Exception means mainly run-time errors that occur at the time of execution of your application. The developer needs to handle that exception otherwise the application will be terminated. Every developer...
Jun 5, 2023
Author: Juan Alberto España Garcia
In this section, we’ll explore the world of unit testing in C# and .NET, learn what unit testing is, why it’s important, and the landscape of testing frameworks and tools available to developers.What is Unit Testing?Unit testing is the process...
Feb 3, 2022
Author: Satish Chandra Gupta
What if programming languages were stocks? And you had to make a portfolio to fetch good returns in 2022?You probably have seen various surveys and analyses listing the most popular programming languages. Those cover the universe of programming languages, like...
Send message
Email
Your name
*Message


© 1999–2023 WebDynamics
1980–... Sergey Drozdov
Area of interests: .NET | .NET Core | C# | ASP.NET | Windows Forms | WPF | Windows Phone | HTML5 | CSS3 | jQuery | AJAX | MS SQL Server | Transact-SQL | ADO.NET | Entity Framework | IIS | OOP | OOA | OOD | WCF | WPF | MSMQ | MVC | MVP | MVVM | Design Patterns | Enterprise Architecture | Scrum | Kanban
LinkedIn
Boosty donation
Donate to support the project
GitHub account
GitHub profile