Table of Contents

TRLS006: Unsafe access to Maybe.Value

Cause

Accessing Maybe.Value without first checking HasValue or using proper guards.

Rule Description

Maybe.Value throws an InvalidOperationException if the Maybe has no value. Accessing it without checking HasValue first can cause runtime exceptions.

How to Fix Violations

Option 1: Check HasValue First

// ❌ Bad - Unsafe access
var customer = maybe.Value;

// ✅ Good - Guarded access
if (maybe.HasValue)
{
    var customer = maybe.Value;
    // Use customer...
}

Option 2: Use TryGetValue

// ✅ Good - Safe extraction
if (maybe.TryGetValue(out var customer))
{
    // Use customer...
}

Option 3: Use GetValueOrDefault

// ✅ Good - With fallback
var customer = maybe.GetValueOrDefault(defaultCustomer);

Option 4: Convert to Result

// ✅ Good - Convert to Result for better composability
return maybe.ToResult(Error.NotFound("Customer not found"))
    .Map(customer => customer.ToDto());

Code Fix

This diagnostic offers an automatic code fix that wraps the unsafe access in an if (maybe.HasValue) guard.

Example Code Fix Transformation

Before:

var maybe = FindCustomer(id);
var customer = maybe.Value;
customer.UpdateEmail(newEmail);

After (automatic):

var maybe = FindCustomer(id);
if (maybe.HasValue)
{
    var customer = maybe.Value;
    customer.UpdateEmail(newEmail);
}

When to Suppress Warnings

This warning can be suppressed in test code where you're explicitly testing the "has value" scenario.

[Fact]
public void Should_FindExistingCustomer()
{
    var maybe = repository.FindById(customerId);
    maybe.HasValue.Should().BeTrue();
    #pragma warning disable TRLS006
    maybe.Value.Name.Should().Be("John");
    #pragma warning restore TRLS006
}

Best Practices

Consider using Result<T> instead of Maybe<T> when you want to provide error information:

// Maybe provides no error context
public Maybe<Customer> FindCustomer(Guid id) { ... }

// Result provides clear error information
public Result<Customer> FindCustomer(Guid id)
{
    var maybe = repository.FindById(id);
    return maybe.ToResult(Error.NotFound($"Customer {id} not found"));
}
  • TRLS003 - Unsafe access to Result.Value