Instruction file imported from hebelmx/ExxerCube.Prisma (
.cursor/rules/1028_ExxerAINullSafety.mdc). Copyright stays with the author.
globs: *.cs description: Comprehensive null safety patterns and null-aware programming
ExxerAI Null Safety Patterns
Meta
Title: ExxerAI Null Safety Patterns Description: Comprehensive null safety patterns and null-aware programming Applies-to: All C# code in ExxerAI project
Requirements
if (string.IsNullOrWhiteSpace(name))
return Result<Agent>.WithFailure("Agent name cannot be empty");
if (config == null)
return Result<Agent>.WithFailure("Agent configuration cannot be null");
var agent = new Agent { Name = name, Configuration = config };
return await _repository.AddAsync(agent, cancellationToken);
}
// ❌ Incorrect: Missing null checks
public async Task<Result<Agent>> CreateAgentAsync(string name, AgentConfiguration config, CancellationToken cancellationToken = default)
{
var agent = new Agent { Name = name, Configuration = config };
return await _repository.AddAsync(agent, cancellationToken);
}
</incorrect-example>
</requirement>
<requirement priority="critical">
**Description**: Use null-aware operators (?.) and null-coalescing (??) appropriately
**Examples**:
<correct-example>
```csharp
// ✅ Correct: Null-aware operators
var agentName = agent?.Name ?? "Unknown";
var taskCount = agent?.Tasks?.Count ?? 0;
var capabilities = agent?.Capabilities?.SupportedTaskTypes?.FirstOrDefault() ?? "default";
// Safe navigation with null checks
if (agent?.Configuration?.Settings != null)
{
ProcessSettings(agent.Configuration.Settings);
}
// Check if operation succeeded (regardless of null value) if (result.IsSuccessMayBeNull) { // Safe to check value, but might be null if (result.IsSuccessNotNull) { var agent = result.Value; // Guaranteed non-null ProcessAgent(agent); } else { // Handle successful operation that returned null LogWarning("Agent not found, but operation succeeded"); } } else { // Handle operation failure LogErrors(result.Errors); }
</correct-example>
<incorrect-example>
```csharp
// ❌ Incorrect: Unsafe Result<T> access
var result = await GetAgentAsync(agentId);
var agent = result.Value; // May be null even if IsSuccess is true
ProcessAgent(agent); // Potential NullReferenceException
// Safe aggregation var totalTasks = agents? .Where(a => a?.Tasks != null) .Sum(a => a.Tasks.Count) ?? 0;
</correct-example>
<incorrect-example>
```csharp
// ❌ Incorrect: Unsafe LINQ
var activeAgents = agents
.Where(a => a.Status == AgentStatus.Active)
.Select(a => a.Name)
.ToList(); // May throw if agents is null or contains null elements
// Safe string formatting var message = $"Agent: {agent?.Name ?? "Unknown"} (Status: {agent?.Status ?? AgentStatus.Unknown})";
</correct-example>
<incorrect-example>
```csharp
// ❌ Incorrect: Unsafe string operations
var displayName = agent.Name.Trim(); // May throw if agent or Name is null
var description = agent.Description; // May be null
var message = $"Agent: {agent.Name}"; // May throw if agent is null
// Safe collection access if (agent?.Capabilities?.SupportedTaskTypes?.Any() == true) { var firstTaskType = agent.Capabilities.SupportedTaskTypes.First(); ProcessTaskType(firstTaskType); }
</correct-example>
<incorrect-example>
```csharp
// ❌ Incorrect: Unsafe collection operations
var taskList = agent.Tasks.ToList(); // May throw if agent or Tasks is null
var hasActiveTasks = agent.Tasks.Any(t => t.Status == TaskStatus.Active); // Multiple null risks