Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The checked keyword in C# explicitly enables arithmetic overflow checking for integral-type operations, enum operations, explicit numeric conversions, and user-defined types implementing checked operators. When an operation inside a checked context produces a result that exceeds the maximum or minimum bounds of the destination data type, the Common Language Runtime (CLR) throws a System.OverflowException instead of silently wrapping or truncating the value. You can apply checked in two ways: as an operator for a single expression, or as a statement block for multiple expressions. Operator Syntax:
int max = int.MaxValue;
int result = checked(max + 1); // Throws System.OverflowException at runtime
Statement Block Syntax:
int max = int.MaxValue;
checked
{
    int result1 = max + 1; // Throws System.OverflowException
    int result2 = max * 2; 
}

Technical Mechanics

  • Affected Types: The checked context applies to integral types (sbyte, byte, short, ushort, int, uint, long, ulong, char, nint, and nuint), enum types (which are backed by integral types), and user-defined struct or class types that implement checked operator overloads.
  • User-Defined Checked Operators (C# 11+): Developers can define custom overflow behavior for user-defined types using the checked modifier on operator overloads. When an operation is invoked inside a checked context, the compiler resolves to the checked variant of the operator if it exists. Note that declaring a checked operator requires also declaring its matching non-checked version to avoid a compile-time error (CS9025).
public struct CustomNumber
{
    public long Value { get; }
    public CustomNumber(long value) => Value = value;

    // Standard operator (resolved in unchecked contexts)
    public static CustomNumber operator +(CustomNumber a, CustomNumber b) => 
        new CustomNumber(a.Value + b.Value);

    // Checked operator (resolved in checked contexts)
    public static CustomNumber operator checked +(CustomNumber a, CustomNumber b) => 
        new CustomNumber(checked(a.Value + b.Value));
        
    // Standard explicit conversion (resolved in unchecked contexts)
    public static explicit operator int(CustomNumber n) => (int)n.Value;

    // Checked explicit conversion (resolved in checked contexts)
    public static explicit operator checked int(CustomNumber n) => checked((int)n.Value);
}
  • Floating-Point and Decimal Types: Floating-point arithmetic operations (float, double) are unaffected by checked and resolve to Infinity on overflow. However, explicit casts from floating-point types to integral types are strictly evaluated for overflow within a checked context. The decimal type always throws an OverflowException on arithmetic overflow, regardless of the checking context.
  • Affected Operations: The context enforces bounds checking on the following operations:
    • Binary arithmetic operators: +, -, *
    • Unary operators: -, ++, --
    • Explicit numeric conversions (casts) between integral types or enums.
    • Explicit numeric conversions (casts) from floating-point types (float, double) to integral types.
    • User-defined operators explicitly marked with the checked modifier.
  • Compile-Time vs. Runtime: By default, C# evaluates non-constant integral expressions at runtime in an unchecked context (unless the /checked compiler flag is enabled). The checked keyword forces the compiler to emit overflow-aware IL (Intermediate Language) instructions. For arithmetic, it emits add.ovf, sub.ovf, or mul.ovf instead of the standard add, sub, or mul instructions. For explicit conversions, it emits conv.ovf.* instructions (e.g., conv.ovf.i4) instead of standard conversion instructions (e.g., conv.i4). Constant expressions are always checked at compile-time, regardless of the presence of the checked keyword, unless explicitly wrapped in an unchecked block.

Lexical Scoping Limitation

The checked environment is strictly lexically scoped. It only applies to the operations textually written within the parentheses or braces. It does not propagate down the call stack to methods invoked within the block.
int Multiply(int a, int b)
{
    return a * b; // Executes in the default context (usually unchecked)
}

void Execute()
{
    checked
    {
        // The method call itself is inside the checked block, 
        // but the arithmetic inside Multiply() is NOT checked.
        // This will silently wrap instead of throwing an exception.
        int result = Multiply(int.MaxValue, 2); 
    }
}
Master C# with Deep Grasping Methodology!Learn More