Operadores de C#

Sugerencia

Este artículo forma parte de la sección Aspectos básicos de los desarrolladores que ya conocen al menos un lenguaje de programación y están aprendiendo C#. Si no está familiarizado con la programación, comience primero con los tutoriales de introducción .

¿Viene de otro idioma? La mayoría de los operadores de este artículo (, , , ||%/!&&!=*==, <, >, operadores de comparación y =) funcionan igual que en Java, C++y JavaScript. -+ Las principales sorpresas para los recién llegados son el comportamiento de división de enteros, la distinción de prefijo/postfijo para ++/--y la forma en que la asignación compuesta se convierte de nuevo al tipo de lado izquierdo.

Un operador combina uno o varios operandos en un solo valor. Ya conoces las expresiones y la precedencia de operadores en las expresiones de C#; este artículo profundiza más en los operadores específicos que usarás a diario.

Operadores aritméticos

Los cinco operadores aritméticos realizan cálculos numéricos.

Operador Name Ejemplo Result
+ Adición 10 + 3 13
- Resta 10 - 3 7
* Multiplicación 10 * 3 30
/ División 10 / 3 3
% Resto 10 % 3 1
int apples = 10;
int oranges = 3;

Console.WriteLine(apples + oranges);  // => 13  (addition)
Console.WriteLine(apples - oranges);  // => 7   (subtraction)
Console.WriteLine(apples * oranges);  // => 30  (multiplication)
Console.WriteLine(apples / oranges);  // => 3   (integer division: truncates toward zero)
Console.WriteLine(apples % oranges);  // => 1   (remainder)

// Integer division always truncates toward zero — the fractional part is discarded
int result = 7 / 2;
Console.WriteLine(result); // => 3, not 3.5

// Truncation applies to negative results too: -7 / 2 is -3, not -4
int negResult = -7 / 2;
Console.WriteLine(negResult); // => -3

// To get a decimal result, at least one operand must be a double or float
double precise = 7.0 / 2;
Console.WriteLine(precise); // => 3.5

// Remainder with negative operands: the sign of the result matches the dividend
Console.WriteLine(-7 % 3);  // => -1  (-7 = 3 × -2 + (-1))
Console.WriteLine(7 % -3);  // => 1   ( 7 = -3 × -2 + 1)

La división de enteros se trunca hacia cero. Cuando ambos operandos son enteros, / descarta la parte fraccionarcional: 7 / 2 es 3, no 3.5. El truncamiento está hacia cero, no hacia el número más pequeño: -7 / 2 es -3 (no -4). Para obtener un resultado decimal, convierta al menos un operando en un tipo de punto flotante: 7.0 / 2 es 3.5. Esto difiere de algunos lenguajes en los que / siempre genera un resultado de punto flotante.

Resto (%) devuelve lo que queda después de la división de enteros: 10 % 3 es 1 porque 10 = 3 × 3 + 1. Resulta útil para recorrer un intervalo fijo (index % length), probar la divisibilidad (n % 2 == 0) y extraer dígitos. Con operandos negativos, el signo del resultado coincide con el signo del dividendo (el operando izquierdo): -7 % 3 es -1 y 7 % -3 es 1.

Operadores unarios

Los operadores unarios actúan sobre un único operando.

int temperature = 20;
int windChill = -5;

int heatIndex = +temperature;   // unary +: value unchanged (rarely needed)
int coldFactor = -windChill;    // unary -: negates the value → 5

Console.WriteLine(heatIndex);   // => 20
Console.WriteLine(coldFactor);  // => 5

bool isRaining = false;
bool isSunny = !isRaining;     // logical NOT: flips true/false
Console.WriteLine(isSunny);    // => True
  • +x (unario más) — deja el valor sin cambios; rara vez se escribe explícitamente, pero es válido.
  • -x (unario menos): niega el valor.
  • !x (NOT lógico): voltea true a false y false a true. Usarás ! a menudo: if (!list.Contains(item)).

Incremento y disminución

++ agrega 1 y -- resta 1. Ambos tienen un formato de prefijo y un formulario postfijo que difieren en qué valor se devuelve:

int counter = 5;

// Prefix: increment first, then use the new value
int a = ++counter;
Console.WriteLine(a);       // => 6
Console.WriteLine(counter); // => 6

// Postfix: use the current value first, then increment
int b = counter++;
Console.WriteLine(b);       // => 6  (value before increment)
Console.WriteLine(counter); // => 7  (incremented after)

// Decrement works the same way
int score = 10;
Console.WriteLine(score--); // => 10 (current value; score becomes 9)
Console.WriteLine(score);   // => 9
  • Prefijo (++i, --i): incrementa o disminuye primero la variable y, a continuación, devuelve el nuevo valor.
  • Postfix (i++, ): devuelve primero el valor actual y, a continuación, i--incrementa o disminuye la variable.

Cuando ++ o -- aparece como una instrucción independiente (no forma parte de una expresión mayor), el prefijo y el postfijo tienen el mismo efecto. La distinción solo importa cuando se usa el resultado, por ejemplo, en una asignación o como argumento de método.

Operadores relacionales

Los operadores relacionales comparan dos valores y devuelven un bool.

Operador Meaning Ejemplo
< Menor que speed < limit
> Mayor que speed > limit
<= Menor o igual que score <= 100
>= Mayor o igual que score >= 0
int speed = 75;
int limit = 60;

Console.WriteLine(speed > limit);   // => True   (greater than)
Console.WriteLine(speed < limit);   // => False  (less than)
Console.WriteLine(speed >= limit);  // => True   (greater than or equal)
Console.WriteLine(speed <= limit);  // => False  (less than or equal)

// Relational operators work on all numeric types and char
// char comparison uses the character's numeric Unicode code point, not alphabetical position
// 'B' (U+0042, value 66) is less than 'A' (U+0041, value 65)? No — 'A' (65) < 'B' (66)
char grade = 'B';
Console.WriteLine(grade >= 'A' && grade <= 'C'); // => True  ('A'=65 <= 'B'=66 <= 'C'=67)

Los operadores relacionales funcionan en todos los tipos numéricos y char. Para char, la comparación usa el valor numérico de punto de código Unicode del carácter, no ningún orden alfabético o específico del dominio. En el ejemplo de grado anterior, 'B' es mayor o igual que 'A' porque 'B' tiene un valor Unicode 66 y 'A' tiene un valor Unicode 65: los números determinan la comparación, no el significado de las calificaciones de letra.

Operadores de igualdad

== y != compruebe si dos valores son iguales o no. != es true cuando los operandos no son iguales, y false cuando lo son.

int expected = 42;
int actual = 42;

Console.WriteLine(actual == expected);  // => True   (values are equal)
Console.WriteLine(actual != expected);  // => False  (true when values are not equal)

string name = "Alice";
Console.WriteLine(name == "Alice");  // => True   (string content matches)
Console.WriteLine(name == "alice");  // => False  (case-sensitive)

int x = 5;
Console.WriteLine(x == 10);  // => False

Para los tipos numéricos y string, la igualdad comprueba los valores. Para los tipos de referencia, el valor predeterminado es identity (si dos variables apuntan al mismo objeto), pero muchos tipos incluidos string e record invalidan esto para comparar el contenido. Para obtener la imagen completa ( cómo funciona la igualdad entre tipos de valor, tipos de referencia, registros y estructuras), consulte Comparaciones de igualdad.

Nota:

C# no tiene un === operador . Escribir === es un error en tiempo de compilación:

// This does not compile — C# has no === operator
bool same = (x === 10);

Si procede de JavaScript, use == para la comparación de valores (C# == ya compara por valor para tipos primitivos y cadenas). Un error habitual relacionado es escribir accidentalmente = (asignación) cuando en realidad querías escribir == (comprobación de igualdad). El compilador detecta los formularios más comunes, pero comprueba de nuevo cualquier if condición que contenga =.

Operadores lógicos condicionales

&& (AND) y || (OR) combinan bool expresiones.

int age = 20;
bool hasTicket = true;

// && (AND): both sides must be true
bool canEnter = age >= 18 && hasTicket;
Console.WriteLine(canEnter); // => True

// || (OR): at least one side must be true
bool freeEntry = age < 5 || age >= 65;
Console.WriteLine(freeEntry); // => False

// Short-circuit: right side is skipped when the result is already determined
// Here, items.Count is never called if items is null
List<string>? items = null;
bool hasItems = items != null && items.Count > 0;
Console.WriteLine(hasItems); // => False  (short-circuits; no NullReferenceException)

Ambos operadores cortocircuitan: dejan de evaluar el operando derecho cuando el resultado ya está determinado.

  • && devuelve false en cuanto la parte izquierda es false. El lado derecho nunca se evalúa.
  • || devuelve true en cuanto la parte izquierda es true. El lado derecho nunca se evalúa.

El comportamiento de cortocircuito tiene una ventaja práctica: puede proteger de forma segura una operación en el lado derecho con una comprobación nula en el lado izquierdo, como se muestra en el ejemplo anterior. Si items es null, && se detiene ahí — nunca se llama a items.Count, por lo que no se produce ninguna excepción NullReferenceException.

Operador condicional ?:

El operador condicional (también denominado operador ternario ) evalúa una de las dos expresiones en función de una condición:

condition ? value-when-true : value-when-false
int temperature2 = 35;

// condition ? value-when-true : value-when-false
string weather = temperature2 > 30 ? "hot" : "comfortable";
Console.WriteLine(weather); // => hot

// Only the matching branch evaluates — the other branch is never run
int divisor = 0;
// The division 10 / divisor is never evaluated because divisor == 0 is true
int safe = divisor == 0 ? -1 : 10 / divisor;
Console.WriteLine(safe); // => -1

El ?: operador siempre evalúa exactamente una rama: el lado que no coincide con la condición nunca se evalúa. Esto hace que sea seguro usar una expresión en una de las partes que fallaría con otras entradas, siempre y cuando la condición la proteja correctamente.

Utilice ?: para opciones simples en línea. Para condiciones múltiples o bloques de código, suele ser más clara una instrucción if/else.

Operadores de asignación

El operador = de asignación simple almacena un valor en una variable:

int level = 1;  // declaration + initialization
level = 5;      // reassignment

La asignación en C# es asociativa por la derecha, lo que significa que a = b = c = 0 se evalúa de derecha a izquierda: c recibe 0, luego b recibe a y, después, 0 recibe 0.

Asignación compuesta

Los operadores de asignación compuesta combinan una operación binaria con la asignación:

Operador Equivalente a
x += y x = x + y
x -= y x = x - y
x *= y x = x * y
x /= y x = x / y
x %= y x = x % y
int level = 1;
level = 5;          // simple assignment: replaces the value
Console.WriteLine(level); // => 5

// Compound assignment: short form of binary operation + assignment
int hp = 100;
hp += 20;   // same as: hp = hp + 20
Console.WriteLine(hp); // => 120
hp -= 10;   // same as: hp = hp - 10
Console.WriteLine(hp); // => 110
hp *= 2;    // same as: hp = hp * 2
Console.WriteLine(hp); // => 220
hp /= 3;    // same as: hp = hp / 3 (integer division)
Console.WriteLine(hp); // => 73
hp %= 7;    // same as: hp = hp % 7
Console.WriteLine(hp); // => 3

La asignación compuesta es más que una forma abreviada. Evalúa el lado izquierdo exactamente una vez y, a continuación, convierte el resultado de nuevo en el tipo izquierdo. Esto importa cuando el lado izquierdo tiene efectos secundarios (como un indexador de array), y por eso la asignación compuesta en una variable byte se compila sin una conversión explícita, mientras que la forma desarrollada no:

// Assignment is right-associative: evaluated right to left
int a2, b2, c2;
a2 = b2 = c2 = 0;     // c2 = 0 first, then b2 = 0, then a2 = 0
Console.WriteLine($"{a2} {b2} {c2}"); // => 0 0 0

// Compound assignment evaluates the left side once and converts back to the LHS type
byte small = 200;
small += 10;  // equivalent to: small = (byte)(small + 10); result is 210
Console.WriteLine(small); // => 210

small += 10 se compila porque el compilador inserta automáticamente la conversión de restricción, el resultado, 210, se ajusta dentro del byte intervalo de 0 a 255. small = small + 10 requeriría una conversión explícita (byte) , ya que la aritmética promueve ambos operandos a int.

Otros operadores de C#

En este artículo se tratan los operadores con los que te encontrarás con más frecuencia en el código del día a día. El lenguaje C# incluye más operadores útiles en escenarios específicos:

  • Operadores de desplazamiento (<<, >>, >>>) : desplaza los bits de un valor entero de izquierda o derecha por un número especificado de posiciones. Operadores lógicos de bits y de enteros (&, |, ^, ~) — combinan o invierten valores enteros bit a bit, útiles en indicadores, máscaras y código de bajo nivel: Operadores de bits y de desplazamiento
  • checked y unchecked — controlan si el desbordamiento de enteros produce una excepción (checked) o se desborda silenciosamente (unchecked): checked y unchecked
  • Operadores nulos (??, ??=, ?., ?[]) — controlan de forma segura los valores null proporcionando valores predeterminados o interrumpiendo el acceso a miembros mediante cortocircuito: Operadores nulos
  • Operadores de comprobación de tipos y de conversión (is, as, typeof, conversión (T)) — comprueban o convierten el tipo en tiempo de ejecución de un valor: Operadores de comprobación de tipos y conversión
  • Operadores de rango e índice (.., ^) : crear intervalos e índices relativos al final para segmentar matrices y intervalos: acceso de miembros y operadores condicionales NULL
  • Asignación de deconstrucción — descompone una tupla o un tipo en variables independientes en una sola expresión: Deconstrucción de tuplas y otros tipos

Véase también