Avoid Return Null Collections

✅ One-liner Summary

Avoid return null; from methods that return collections — return empty collections instead.

💡 Short Explanation

When a method returns a collection type, returning null forces callers to check for null before using the collection.
This leads to defensive programming patterns and potential null reference exceptions.

🚫 Bad Example

This approach forces callers to handle null cases:

public List<User> GetActiveUsers()
{
    if (!_userService.IsAvailable())
    {
        return null; // ⚠️ Forces null checks everywhere
    }
    
    return _userService.GetUsers().Where(u => u.IsActive).ToList();
}

Usage requires defensive programming:

var users = GetActiveUsers();
if (users != null) // ⚠️ Required null check
{
    foreach (var user in users)
    {
        // Process user
    }
}

✅ Good Example

Return empty collections instead of null:

public List<User> GetActiveUsers()
{
    if (!_userService.IsAvailable())
    {
        return new List<User>(); // ✅ Empty collection
    }
    return _userService.GetUsers().Where(u => u.IsActive).ToList();
}

Usage is clean and safe:

var users = GetActiveUsers();
foreach (var user in users) // ✅ No null check needed
{
    // Process user
}

🧠 Key Takeaways

  • Return empty collections instead of null
  • Eliminates null reference exceptions
  • Reduces defensive programming overhead
  • Avoids potential runtime errors if checks are missed

🛠️ Which Empty Collection Should You Return?

The specific empty collection you return should match your method’s return type. Here’s a guide to common collection types and how to handle them.

Return TypeRecommended Return Statement
IEnumerable<T>return Enumerable.Empty<T>();
ICollection<T>return new List<T>();
IReadOnlyCollection<T>return Array.Empty<T>();
IDictionary<K, V>return new Dictionary<K, V>();
List<T>return new List<T>();
T[] (Array)return Array.Empty<T>();

✨ The C# 12 Way: return []

With C# 12 and later, you can use collection expressions ([]) to create an empty collection for any compatible type. The compiler infers the correct type from the method signature. This is now the recommended approach for its conciseness and clarity.

public List<User> GetActiveUsers()
{
    if (!_userService.IsAvailable())
    {
        return []; // ✅ C# 12: Clean, concise, and type-safe.
    }
    
    return _userService.GetUsers().Where(u => u.IsActive).ToList();
}

To enforce this rule in your project, add the following to your .editorconfig file:

# IDE0301: Simplify collection initialization
dotnet_diagnostic.IDE0301.severity = warning

This will make the compiler treat not using collection expressions as a warning, ensuring consistent code style across your team.