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 - operator in C# functions as both a unary operator for numeric negation and a binary operator for arithmetic subtraction, enumeration subtraction, delegate removal, and pointer arithmetic. Its behavior, return type, and overflow mechanics are resolved at compile-time based on the arity of the operation, the static types of its operands, and the evaluation context.

Unary Negation

When applied to a single operand, the - operator computes the numeric negation of that operand, effectively subtracting the operand from zero.
  • Supported Types: Predefined for int, long, float, double, and decimal.
  • Type Mechanics: When the unary - operator is applied to a uint, the operand is implicitly promoted to a long, and the operation returns a long. The operator is not defined for ulong; attempting to apply it to a ulong results in a compile-time error (CS0023).
  • Overflow Mechanics: The two’s complement representation of integers means the absolute value of int.MinValue and long.MinValue exceeds the maximum positive value of their respective types. Applying the unary - to these minimum values in an unchecked context results in a wrap-around, returning the minimum value itself. In a checked context, this operation throws a System.OverflowException.
int positiveInt = 5;
int negativeInt = -positiveInt;

uint unsignedInt = 10U;
long negatedUnsigned = -unsignedInt; // Implicitly promoted to long

int min = int.MinValue;
int uncheckedNegation = unchecked(-min); // Evaluates to int.MinValue
int checkedNegation = checked(-min);     // Throws System.OverflowException

Binary Subtraction

When applied to two operands, the - operator computes the arithmetic difference between the left operand (minuend) and the right operand (subtrahend).
  • Supported Types: Predefined for all standard numeric types (int, uint, long, ulong, float, double, decimal).
  • Type Mechanics: If the operands are of different types, C# applies implicit numeric promotions to convert them to a common type before performing the subtraction. The return type matches this promoted type.
  • Overflow Mechanics: For integral types, if the mathematical difference cannot be represented within the bounds of the return type, an arithmetic overflow occurs. In an unchecked context, the high-order bits are discarded, resulting in a wrap-around. In a checked context, the operation throws a System.OverflowException. Floating-point subtraction (float, double) never throws an overflow exception; instead, it yields positive or negative infinity.
int a = 10;
int b = 3;
int difference = a - b;

float c = 5.5f;
double d = 2.2;
double floatDoubleDifference = c - d; // float is promoted to double

int max = int.MaxValue;
int overflowUnchecked = unchecked(max - (-1)); // Evaluates to int.MinValue
int overflowChecked = checked(max - (-1));     // Throws System.OverflowException

Lifted Operators for Nullable Types

For nullable value types (T?), C# automatically provides lifted versions of the predefined unary and binary - operators. The lifted operator evaluates the HasValue property of its operands. If either or both operands evaluate to null, the result of the operation is null. Otherwise, the operator unwraps the underlying values, applies the standard - operator, and wraps the result back into a nullable type.
int? val1 = 10;
int? val2 = null;

int? binaryResult = val1 - val2; // Evaluates to null
int? unaryResult = -val2;        // Evaluates to null

DateTime and TimeSpan Subtraction

C# provides predefined binary - operators for the System.DateTime, System.DateTimeOffset, and System.TimeSpan structs to handle chronological arithmetic:
  1. DateTime and DateTime: Subtracting a DateTime from another DateTime yields a System.TimeSpan representing the duration between the two points in time.
  2. DateTime and TimeSpan: Subtracting a TimeSpan from a DateTime yields a new DateTime decremented by the specified duration.
  3. TimeSpan and TimeSpan: Subtracting a TimeSpan from another TimeSpan yields a new TimeSpan representing the difference between the two durations.
System.DateTime d1 = new System.DateTime(2023, 1, 10);
System.DateTime d2 = new System.DateTime(2023, 1, 5);
System.TimeSpan duration = d1 - d2; // Yields TimeSpan representing 5 days

System.DateTime decremented = d1 - duration; // Yields DateTime(2023, 1, 5)

Enumeration Subtraction

C# provides predefined binary - operators for all enum types, supporting two distinct operations:
  1. Enum and Enum: Subtracting two enum values of the same type yields the difference between their underlying numeric values. The return type is the underlying integral type of the enumeration.
  2. Enum and Integer: Subtracting an integer from an enum value yields a new enum value decremented by the integer amount. The return type is the enumeration type itself.
System.DayOfWeek currentDay = System.DayOfWeek.Wednesday;
System.DayOfWeek previousDay = currentDay - 2; // Enum and Integer yields Enum (Monday)

int daysBetween = System.DayOfWeek.Friday - System.DayOfWeek.Monday; // Enum and Enum yields Int32 (4)

Delegate Removal

For operands of concrete delegate types (such as System.Action, System.Func<T>, or custom delegate signatures), the binary - operator performs delegate removal. It evaluates the invocation lists of both operands. The operator is not defined on the System.Delegate base class itself; attempting to use it on variables typed strictly as System.Delegate results in a compile-time error (CS0019).
  • Mechanics: If the right operand’s invocation list is a contiguous sublist of the left operand’s invocation list, the operator returns a new delegate with that sublist removed. If the right operand’s invocation list matches multiple sublists within the left operand’s invocation list, the - operator removes only the last matching contiguous sublist. If the right operand is not found, or if the right operand is null, it returns the left operand unchanged. If the removal results in an empty invocation list, the operator returns null.
System.Action action1 = () => System.Console.Write("A");
System.Action action2 = () => System.Console.Write("B");

System.Action combined = action1 + action2;
System.Action removed = combined - action2; // Returns a delegate equivalent to action1

Pointer Arithmetic

In an unsafe context, the binary - operator supports pointer arithmetic with two distinct signatures:
  1. Pointer and Integer: Subtracting an integer offset from a pointer returns a new pointer of the same type, decremented by the offset multiplied by the size of the pointer’s underlying type.
  2. Pointer and Pointer: Subtracting a pointer from another pointer of the same type returns a long representing the distance (in elements, not bytes) between the two memory addresses.
unsafe
{
    int[] numbers = new int[5];
    fixed (int* ptr1 = &numbers[0])
    fixed (int* ptr2 = &numbers[3])
    {
        int* decrementedPtr = ptr2 - 1; // Pointer and Integer
        long elementDistance = ptr2 - ptr1; // Pointer and Pointer yields 3L
    }
}

Operator Overloading

User-defined types (struct or class) can overload the - operator to define custom negation or subtraction logic. Overloads must be declared as public static. If a type overloads the binary - operator, it does not automatically overload the -= compound assignment operator; however, C# automatically evaluates x -= y as x = x - y using the overloaded binary operator.
public readonly struct Point
{
    public readonly int X;
    public readonly int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    // Unary overload signature
    public static Point operator -(Point p)
    {
        return new Point(-p.X, -p.Y);
    }

    // Binary overload signature
    public static Point operator -(Point left, Point right)
    {
        return new Point(left.X - right.X, left.Y - right.Y);
    }
}
Master C# with Deep Grasping Methodology!Learn More