csharp-nullable-types
Use when C# nullable reference types and value types for null safety, nullable annotations, and patterns for handling null values.
What this skill does
# C# Nullable Types
Nullable types in C# help prevent null reference exceptions, one of the most
common programming errors. C# 8.0 introduced nullable reference types,
providing compile-time null-safety checking. This skill covers nullable value
types, nullable reference types, null-coalescing operators, and patterns for
safe null handling.
## Nullable Value Types
Value types (int, double, bool, struct) normally cannot be null. Nullable
value types enable representing "no value" state.
```csharp
using System;
public class NullableValueTypes
{
// Declaration
public void Declaration()
{
int? nullableInt = null;
int? anotherInt = 42;
double? nullableDouble = null;
bool? nullableBool = true;
// Generic syntax (equivalent)
Nullable<int> genericNullable = null;
}
// Checking for null
public void NullChecking()
{
int? value = GetNullableValue();
// HasValue property
if (value.HasValue)
{
int actualValue = value.Value;
Console.WriteLine(actualValue);
}
// Comparison with null
if (value != null)
{
Console.WriteLine(value.Value);
}
// Null-conditional operator
int? doubled = value?.GetHashCode();
}
// Getting values
public void GettingValues()
{
int? value = 42;
// Value property (throws if null)
int val1 = value.Value;
// GetValueOrDefault
int val2 = value.GetValueOrDefault(); // Returns 0 if null
int val3 = value.GetValueOrDefault(10); // Returns 10 if null
// Null-coalescing operator
int val4 = value ?? 0; // Returns 0 if null
}
// Nullable in expressions
public void NullableExpressions()
{
int? a = 10;
int? b = 20;
int? c = null;
// Arithmetic (null if any operand is null)
int? sum1 = a + b; // 30
int? sum2 = a + c; // null
// Comparison
bool? equal = a == b; // false
bool? greater = a > c; // null
// Logical operators
bool? and = (a > 5) & (c > 5); // null
}
// Nullable structs
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
public void NullableStructs()
{
Point? point = null;
if (point.HasValue)
{
int x = point.Value.X;
int y = point.Value.Y;
}
// Null-conditional with structs
int? x = point?.X;
}
private int? GetNullableValue() => null;
}
```
## Nullable Reference Types
C# 8.0+ provides nullable reference types, enabling compile-time null-safety
for reference types.
```csharp
#nullable enable
using System;
using System.Collections.Generic;
public class NullableReferenceTypes
{
// Non-nullable by default
public string Name { get; set; } = string.Empty;
// Explicitly nullable
public string? MiddleName { get; set; }
// Constructor
public NullableReferenceTypes(string name, string? middleName = null)
{
Name = name; // Must be non-null
MiddleName = middleName; // Can be null
}
// Method with nullable parameters
public string FormatName(string firstName, string? middleName,
string lastName)
{
// Compiler warns if middleName used without null check
if (middleName != null)
{
return $"{firstName} {middleName} {lastName}";
}
return $"{firstName} {lastName}";
}
// Nullable return type
public string? FindPerson(int id)
{
// May return null
return id > 0 ? "Found" : null;
}
// Collections of nullable types
public void CollectionExamples()
{
// List of non-null strings
List<string> names = new List<string> { "Alice", "Bob" };
// List of nullable strings
List<string?> nullableNames = new List<string?>
{
"Alice", null, "Charlie"
};
// Dictionary with nullable values
Dictionary<string, string?> dict =
new Dictionary<string, string?>
{
{ "key1", "value1" },
{ "key2", null }
};
}
// Nullable generic types
public T? FindById<T>(int id) where T : class
{
// Returns null if not found
return default(T);
}
// Not-null assertion operator
public void NotNullAssertion()
{
string? maybeName = GetName();
// Tell compiler this won't be null (use with caution!)
string name = maybeName!;
}
private string? GetName() => null;
}
```
## Null-Coalescing Operators
Null-coalescing operators provide concise null handling.
```csharp
#nullable enable
using System;
using System.Collections.Generic;
public class NullCoalescingOperators
{
// Null-coalescing operator (??)
public string GetDisplayName(string? name)
{
// Returns "Unknown" if name is null
return name ?? "Unknown";
}
// Chaining
public string GetFirstNonNull(string? a, string? b, string? c)
{
return a ?? b ?? c ?? "Default";
}
// Null-coalescing assignment (??=)
public void NullCoalescingAssignment()
{
string? name = null;
// Assign only if null
name ??= "Default Name"; // name is now "Default Name"
name ??= "Another Name"; // name stays "Default Name"
}
// With collections
public void CollectionCoalescing()
{
List<string>? list = null;
// Initialize if null
list ??= new List<string>();
// Add items
list.Add("item");
}
// In property initialization
private List<string>? _items;
public List<string> Items => _items ??= new List<string>();
// Complex expressions
public string ComplexCoalescing(User? user)
{
// Multiple levels
return user?.Profile?.DisplayName ??
user?.Email ??
"Guest";
}
public class User
{
public Profile? Profile { get; set; }
public string? Email { get; set; }
}
public class Profile
{
public string? DisplayName { get; set; }
}
}
```
## Null-Conditional Operator
The null-conditional operator safely accesses members and calls methods on
potentially null references.
```csharp
#nullable enable
using System;
using System.Collections.Generic;
public class NullConditionalOperator
{
public class Person
{
public string Name { get; set; } = string.Empty;
public Address? Address { get; set; }
public List<string>? PhoneNumbers { get; set; }
}
public class Address
{
public string City { get; set; } = string.Empty;
public string? PostalCode { get; set; }
}
// Basic null-conditional
public string? GetCity(Person? person)
{
// Returns null if person or Address is null
return person?.Address?.City;
}
// With indexers
public string? GetFirstPhone(Person? person)
{
// Returns null if person, PhoneNumbers is null, or empty
return person?.PhoneNumbers?[0];
}
// With method calls
public int? GetNameLength(Person? person)
{
return person?.Name.Length;
}
// Combining operators
public string GetCityOrDefault(Person? person)
{
return person?.Address?.City ?? "Unknown";
}
// With arrays
public string? GetFirstItem(string[]? items)
{
return items?[0];
}
// With delegates
public void InvokeCallback(Action? callback)
{
callback?.Invoke();
}
// With events
public event EventHandler? DataChanged;
public void OnDataChanged()
{
DataChanged?.Invoke(this, EventArgs.Empty);
}
// Chaining multiple operations
pRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.