Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Tip
Эта статья является частью раздела "Основы" для разработчиков , которые уже знают хотя бы один язык программирования и учат C#. Если вы не знакомы с программированием, сначала начните с учебных пособий по началу работы.
Вы пришли из другого языка? Выражения в C# работают так же, как и в Java, C++и JavaScript. Стоит отметить одно различие: операторы составного присваивания, такие как +=, и оператор инкремента ++ в C# являются выражениями, поэтому они могут использоваться как часть более крупных выражений.
Выражение — это фрагмент кода, который компилятор вычисляет для создания значения — числа, строки, ссылки или abool. Например, 3 + 4 * 2 — это выражение, которое имеет значение целого числа 11, а total > 10 — это выражение, которое имеет значение true или false.
Самыми простыми выражениями являются литералы (например42, или"hello") и имена переменных (напримерtotal). Вы создаете более сложные выражения, сочетая более простые с операторами.
Выражения и инструкции
Выражение создает значение.
Инструкция представляет собой полную инструкцию, выполняемую программой. Многие инструкции содержат выражения. Например, int total = 3 + 4 * 2; — это инструкция объявления переменной. Компилятор вычисляет выражение 3 + 4 * 2инициализатора, которое создает 11и присваивает это значение новой переменной total.
Вы можете представить выражение как фразу, а оператор C# — как полное предложение. Эти рабочие определения помогут вам понять формальную терминологию и пояснения, с которыми вы будете сталкиваться по мере дальнейшего изучения C#, хотя при обычном программировании вам редко приходится сознательно помнить об этом различии.
Объединение выражений
Выражения можно объединить. Рассмотрим 3 + 4 * 2. Это одно выражение фактически содержит два небольших выражения: выражение 4 * 2умножения и сложение3 + <result>. При объединении выражений C# требуется правило, чтобы решить, какой из них необходимо сначала оценить. Это правило является приоритетом оператора.
Вам не нужно запоминать полную иерархию приоритета. В следующем разделе кратко описаны обычные группы, а скобки всегда позволяют явно задать порядок, если вы не уверены.
Приоритет оператора
Приоритет операторов определяет, как составное выражение группируется в подвыражения. Эта концепция аналогична правилам порядка операций из математического класса. Оператор с более высоким приоритетом привязывается более тесно к операндам. Выражение построено так, как будто эти операнды заключены в скобки вместе. В 3 + 4 * 2* имеет более высокий приоритет, чем +, поэтому выражение группируется как 3 + (4 * 2), а не (3 + 4) * 2.
C# имеет более приоритетные группы, чем четыре, приведенные здесь. Эти дополнительные группы применяют знакомые правила ( например, умножение перед добавлением) и охватывают полный набор операторов. Следующие группы охватывают то, с чем вы чаще всего сталкиваетесь в повседневной работе с кодом:
-
Первичные, унарные и диапазоны — это три отдельные группы приоритета, все из которых привязываются более тесно, чем арифметические. Это резюме объединяет их в один этап, поскольку на практике все они применяются до выполнения арифметических операций.
-
Первичные операторы — доступ к члену (
x.y), вызовы методов (f()), индексирование (a[i]) и условный доступ с проверкой на null (?.,?[]) — имеют наивысший приоритет. -
Унарные операторы применяются к одному операнду: отрицание (
-x), логическое НЕ (!flag), префиксный инкремент (++i) и постфиксный инкремент (i++). - Оператор диапазона (
..) создает диапазоны индексов для выражений среза, напримерarray[1..4].
-
Первичные операторы — доступ к члену (
-
Арифметика —
*,/,%связываются сильнее, чем+и-. Умножение и деление происходят перед добавлением и вычитанием. -
Сравнение —
<,>,<=,>=,==,!=имеют более низкий приоритет, чем арифметические операции, поэтому арифметические операции выполняются до сравнения. -
Логические операторы —
&&и||имеют самый низкий приоритет среди распространённых операторов, поэтому сравнения выполняются до логического объединения.
Этот приоритет означает, что выражение score + bonus > threshold && attempts < maxAttempts вычисляется именно так, как это читается: сложить score и bonus, сравнить сумму с attempts, сравнить maxAttempts с threshold, а затем объединить два результата bool с помощью &&. Добавление скобок, чтобы явно обозначить каждую группировку, показывает ту же структуру: ((score + bonus) > threshold) && (attempts < maxAttempts).
Полные иерархии приоритета, охватывающие каждый оператор, см. в разделе операторов и выражений C#.
Используйте скобки, чтобы сделать смысл понятнее
Скобки переопределяют приоритет операций и одновременно поясняют ваше намерение. Если порядок не очевиден из указанных выше групп, добавьте скобки:
int score = 80;
int bonus = 15;
int threshold = 90;
bool eligible = true;
// Without parentheses: || binds less tightly than &&, so this reads as:
// eligible && (score + bonus > threshold) || bonus > 20
bool result1 = eligible && score + bonus > threshold || bonus > 20;
// With parentheses: forces the || to combine two complete conditions
bool result2 = (eligible && score + bonus > threshold) || bonus > 20;
Console.WriteLine(result1); // => True
Console.WriteLine(result2); // => True
// Parentheses can also change the result:
bool isAdmin = false;
bool isOwner = true;
// Without: && binds tighter, so: (isAdmin && isOwner) || true
bool access1 = isAdmin && isOwner || true;
// With: forces the || to run first
bool access2 = isAdmin && (isOwner || true);
Console.WriteLine(access1); // => True (false && true is false; false || true is true)
Console.WriteLine(access2); // => False (false && anything is false)
Последние две строки показывают, что скобки могут изменить результат, а не только стиль. Когда && и || появится вместе, добавьте скобки, чтобы определить, какое условие объединяет сначала. Читатель, который видит (isAdmin && isOwner) || isSuperUser, сразу понимает замысел.
Как вычисляются выражения
Понять, как C# вычисляет составные выражения, будет проще, если использовать аналогию. Подумайте о работе с сложной математической проблемой с карандашом и бумагой: вы определяете самую внутреннюю или самую высокую приоритетность под-выражения, вычисляете его промежуточное значение, записываете результат, а затем повторяете с помощью следующего под-выражения — продолжая до тех пор, пока не достигнете окончательного ответа.
C# следует одному и тому же процессу, руководствуясь двумя правилами:
Правило 1. Операнды оценивают слева направо. Для любого двоичного выражения оба операнда должны быть полностью оценены перед применением оператора. C# сначала вычисляет левый операнд, затем правый, а затем выполняет операцию.
Правило 2: Некоторые операторы используют сокращённое вычисление. Некоторые операторы перестают оценивать, как только результат определен, пропуская все оставшиеся операнды:
-
&&(условное И): возвращаетfalse, как только значение левой части равноfalse. Правая сторона никогда не вычисляется. -
||(условное ИЛИ): возвращаетtrue, как только левая часть равнаtrue. Правая сторона никогда не вычисляется. -
?:(условно/ternary): вычисляет только ветвь, соответствующую условию, — другая ветвь никогда не вычисляется. -
?.(null-условный доступ к члену) и?[](null-условный доступ к элементу): немедленно прекращают выполнение и возвращаютnull, если левая часть равнаnull, пропуская доступ к члену или обращение по индексу. -
??=(назначение с объединением null): назначает правую сторону только в том случае, если левая сторона .null
Оценка бумаги и карандаша
Рассмотрим выражение 3 + 6 / 2. Несмотря на то что в порядке чтения первым стоит сложение, / имеет более высокий приоритет, чем +, поэтому именно 6 / 2 является подвыражением, которое вычисляется первым. Решая это шаг за шагом — точно так же, как на бумаге:
3 + 6 / 2
↓ (evaluate 6 / 2 → 3)
3 + 3
↓ (evaluate 3 + 3 → 6)
6
// 3 + 6 / 2
// Step 1: 6 / 2 has higher precedence → interim value 3
// Step 2: 3 + 3 → final result 6
int result = 3 + 6 / 2;
Console.WriteLine(result); // => 6
Промежуточное значение 3 , созданное путем 6 / 2 , становится правым операндом +, а окончательный результат — 6. Каждое под-выражение создает промежуточное значение; эти промежуточные значения питают следующее под-выражение, пока не останется только одно значение.
Ассоциативность — это связанная концепция: когда два оператора имеют одинаковый приоритет, ассоциативность решает, какой из них идет первым. Большинство операторов C# являются левоассоциативными, то есть группируются слева направо. Так a - b - c же, как (a - b) - c, а не a - (b - c).
Оценка короткого канала на практике
Сокращённое вычисление особенно полезно при проверке на null:
string? text = null;
// Safe: second condition runs only when text is not null
bool hasContent = text != null && text.Length > 0;
Console.WriteLine(hasContent); // => False (short-circuits after null check; no NullReferenceException)
text = "hello";
hasContent = text != null && text.Length > 0;
Console.WriteLine(hasContent); // => True
// || short-circuits on true: right side is never evaluated when left side is true
string word = "hello";
bool anyMatch = word.StartsWith("h") || word.StartsWith("x");
Console.WriteLine(anyMatch); // => True (right side never evaluated)
// ?. short-circuits on null: returns null without accessing .Length
string? maybeNull = null;
int? length = maybeNull?.Length; // length is null; no NullReferenceException
Console.WriteLine(length.HasValue); // => False
text != null && text.Length > 0 безопасен, так как второе условие выполняется только если text — не null. Аналогичным образом ?. останавливает вычисление, когда встречает ссылку null, что позволяет избежать NullReferenceException без явной проверки if.
Более широкий взгляд на операторы, безопасные с значением NULL, см. в разделе "Операторы NULL C#".
См. также
- Операторы и выражения C# (справочник по языку) — полная таблица приоритета и каждый оператор
- Арифметические операторы, операторы сравнения, логические операторы и операторы присваивания — подробно о повседневных операторах
-
Сравнение на равенство — как работают
==,!=иEquals -
Операторы C# NULL —
?.,??и??= - Булевы логические операторы