Claude
Skills
Sign in
Back

csharp-nullable-types

Included with Lifetime
$97 forever

Use when C# nullable reference types and value types for null safety, nullable annotations, and patterns for handling null values.

General

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
    p

Related in General