C#-operatorer

Tips/Råd

Den här artikeln är en del av avsnittet Grunderna för utvecklare som redan känner till minst ett programmeringsspråk och lär sig C#. Om du inte har använt programmering tidigare börjar du med självstudierna Komma igång först.

Kommer du från ett annat språk? De flesta operatorer i den här artikeln (+, , *-, /, %&&, ||, !, ==, !=, <, >jämförelseoperatorer och =) fungerar på samma sätt som i Java, C++och JavaScript. De största överraskningarna för nykomlingar är hur heltalsdivision fungerar, skillnaden mellan prefix och postfix för ++/--, och hur sammansatt tilldelning konverterar tillbaka till typen på vänster sida.

En operator kombinerar en eller flera operander till ett enda värde. Du känner redan till uttryck och operatorprioret från C#-uttryck. Den här artikeln går djupare in på de specifika operatorer som du använder varje dag.

Aritmetiska operatorer

De fem aritmetiska operatorerna utför numeriska beräkningar.

Operator Namn Example Result
+ Tillägg 10 + 3 13
- Subtraktion 10 - 3 7
* Multiplikation 10 * 3 30
/ Division 10 / 3 3
% Rest 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)

Heltalsdivision avrundas mot noll. När båda operanderna är heltal ignorerar / decimaldelen: 7 / 2 är 3, inte 3.5. Avkortning sker mot noll, inte mot det lägre talet: -7 / 2 är -3 (inte -4). Om du vill få ett decimalresultat, måste minst en av operanderna vara av en flyttalstyp: 7.0 / 2 är 3.5. Detta skiljer sig från vissa språk där / alltid skapar ett flyttalsresultat.

Rest (%) returnerar det som blir över efter heltalsdivision: 10 % 3 är 1 eftersom 10 = 3 × 3 + 1. Det är användbart för att iterera över ett fast intervall (index % length), testa delbarhet (n % 2 == 0) och extrahera siffror. Med negativa operander matchar resultatets tecken på utdelningen (den vänstra operanden): -7 % 3 är -1 och 7 % -3 är 1.

Unary-operatorer

Unary-operatorer agerar på en enda operand.

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 (unärt plus) — lämnar värdet oförändrat; skrivs sällan ut uttryckligen men är giltigt.
  • -x (unary minus) – negerar värdet.
  • !x (logiskt INTE) – vänder true till false och false till true. Du använder ! ofta: if (!list.Contains(item)).

Öka och minska

++ lägger till 1 och -- subtraherar 1. Båda har ett prefixformulär och ett postfixformulär som skiljer sig åt där värdet returneras:

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
  • Prefix (++i, --i): ökar eller minskar variabeln först och returnerar sedan det nya värdet.
  • Postfix (i++, i--): returnerar det aktuella värdet först och sedan ökar eller minskar variabeln.

När ++ eller -- visas som en fristående instruktion (inte en del av ett större uttryck) har prefixet och postfixet samma effekt. Skillnaden spelar bara roll när resultatet används , till exempel i en tilldelning eller som ett metodargument.

Relationsoperatorer

Relationsoperatorer jämför två värden och returnerar ett bool.

Operator Meaning Example
< Mindre än speed < limit
> Större än speed > limit
<= Mindre än eller lika med score <= 100
>= Större än eller lika med 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)

Relationsoperatorer arbetar med alla numeriska typer och char. För charanvänder jämförelse tecknets numeriska Unicode-kodpunktsvärde, inte någon alfabetisk eller domänspecifik ordning. I betygsexemplet ovan 'B' är större än eller lika 'A' med eftersom 'B' har Unicode-värde 66 och 'A' har Unicode-värde 65 – siffrorna bestämmer jämförelsen, inte innebörden av bokstavsbetygen.

Likhetsoperatorer

== och != kontrollera om två värden är lika med eller inte. != är true när operanderna inte är lika, och false när de är det.

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

För numeriska typer och stringtestar likhet värdena. För referenstyper är standardvärdet identitet (om två variabler pekar på samma objekt), men många typer inkluderar string och record åsidosätter detta för att jämföra innehåll. Den fullständiga bilden – hur likhet fungerar mellan värdetyper, referenstyper, poster och structs – finns i Likhetsjämförelser.

Note

C# har inte någon operator ===. Att skriva === är ett kompileringsfel:

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

Om du kommer från JavaScript använder du == för att jämföra värden (C# == jämför redan efter värde för primitiva typer och strängar). En vanlig relaterad bugg är att oavsiktligt skriva = (tilldelning) där du menade == (likhetskontroll). Kompilatorn fångar de vanligaste formulären, men dubbelkollar alla if villkor som innehåller =.

Villkorsstyrda logiska operatorer

&& (AND) och || (OR) kombinerar bool uttryck.

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)

Båda operatorerna kortsluter: de hoppar över att utvärdera rätt operand när resultatet redan har fastställts.

  • && returnerar false så snart den vänstra sidan är false. Den högra sidan utvärderas aldrig.
  • || returnerar true så snart den vänstra sidan är true. Den högra sidan utvärderas aldrig.

Kortslutningsbeteende har en praktisk fördel: du kan på ett säkert sätt skydda en åtgärd på höger sida med en null-kontroll på vänster sida, som exemplet ovan visar. Om items är null, stannar det där — items.Count anropas aldrig, så ingen NullReferenceException kastas.

Villkorsoperator ?:

Den villkorsstyrda operatorn (kallas även ternary-operatorn ) utvärderar ett av två uttryck baserat på ett villkor:

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

Operatorn ?: utvärderar alltid exakt en gren – den sida som inte matchar villkoret utvärderas aldrig. Detta gör det säkert att använda ett uttryck på den ena sidan som skulle ge fel för andra indatavärden, så länge villkoret på rätt sätt skyddar mot det.

Använd ?: för enkla, infogade alternativ. För flervägsvillkor eller kodblock är en if/else instruktion vanligtvis tydligare.

Tilldelningsoperatorer

Den enkla tilldelningsoperatorn = lagrar ett värde i en variabel:

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

Tilldelning i C# är högerassociativ, vilket innebär att a = b = c = 0 beräknas från höger till vänster: c tilldelas 0, sedan tilldelas 0b, och sedan tilldelas 0a.

Sammansatt tilldelning

Sammansatta tilldelningsoperatorer kombinerar en binär åtgärd med tilldelning:

Operator Likvärdig med
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

Sammansatt tilldelning är mer än bara en förkortning. Det utvärderar vänsterledet exakt en gång och omvandlar sedan resultatet tillbaka till vänsterledets typ. Detta är viktigt när den vänstra sidan har biverkningar (som en matrisindexerare), och det är därför sammansatt tilldelning på en byte variabel kompileras utan explicit gjutning medan det expanderade formuläret inte:

// 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 kompileras eftersom kompilatorn infogar den smala konverteringen automatiskt – resultatet, 210, passar inom byte intervallet 0–255. small = small + 10 skulle kräva en explicit (byte) typkonvertering, eftersom aritmetiken omvandlar båda operanderna till int.

Andra C#-operatorer

Den här artikeln beskriver de operatorer som du stöter på mest i den dagliga koden. C#-språket innehåller fler operatorer som är användbara i specifika scenarier:

  • Skiftoperatorer (<<, >>, >>>) – flytta bitar av ett heltalsvärde åt vänster eller höger med ett angivet antal positioner. Logiska operatorer för bitvis och heltal (&, |, ^, ~) – kombinera eller invertera heltalsvärden en bit i taget, användbara i flaggor, masker och lågnivåkod: Bitvis- och skiftoperatorer
  • checked och unchecked – styr om heltalsöverskridning utlöser ett undantag (checked) eller slår runt utan varning (unchecked): Checked and unchecked
  • Null-operatorer (??, ??=, ?., ?[]) – hanterar null värden på ett säkert sätt genom att tillhandahålla standardvärden eller kortslutande medlemsåtkomst: Null-operatorer
  • Typtest- och konverteringsoperatorer (is, as, typeof, cast (T)) – kontrollera eller konvertera ett värdes körningstyp: Typtestnings- och gjutningsoperatorer
  • Intervall- och indexoperatorer (.., ^) – skapa intervall och slutrelativa index för segmentering av matriser och intervall: Medlemsåtkomst och null-villkorsstyrda operatorer
  • Dekonstruktionstilldelning – packa upp en tuppel eller typ i enskilda variabler i ett enda uttryck: Dekonstruera tupplar och andra typer

Se även