Последнее обновление: 19.06.2017
В C# используется большинство операций, которые применяются и в других языках программирования. Операции представляют определенные действия над операндами - участниками операции. В качестве операнда может выступать переменной или какое-либо значение (например, число). Операции бывают унарными (выполняются над одним операндом), бинарными - над двумя операндами и тернарными - выполняются над тремя операндами. Рассмотрим все виды операций.
Бинарные арифметические операции:
Операция сложения двух чисел:
Int x = 10; int z = x + 12; // 22
Операция вычитания двух чисел:
Int x = 10; int z = x - 6; // 4
Операция умножения двух чисел:
Int x = 10; int z = x * 5; // 50
операция деления двух чисел:
Int x = 10; int z = x / 5; // 2 double a = 10; double b = 3; double c = a / b; // 3.33333333
При делении стоит учитывать, что если оба операнда представляют целые числа, то результат также будет округляться до целого числа:
Double z = 10 / 4; //результат равен 2
Несмотря на то, что результат операции в итоге помещается в переменную типа double, которая позволяет сохранить дробную часть, но в самой опеации участвуют два литерала, которые по умолчанию рассматриваются как объекты int, то есть целые числа, и результат то же будет целочисленный.
Для выхода из этой ситуации необходимо определять литералы или переменные, участвующие в операции, именно как типы double или float:
Double z = 10.0 / 4.0; //результат равен 2.5
Операция получение остатка от целочисленного деления двух чисел:
Double x = 10.0; double z = x % 4.0; //результат равен 2
Также есть ряд унарных операций, в которых принимает участие один операнд:
Операция инкремента
Инкремент бывает префиксным: ++x - сначала значение переменной x увеличивается на 1, а потом ее значение возвращается в качестве результата операции.
И также существует постфиксный инкремент: x++ - сначала значение переменной x возвращается в качестве результата операции, а затем к нему прибавляется 1.
Операция декремента или уменьшения значения на единицу. Также существует префиксная форма декремента (--x) и постфиксная (x--).
Int x1 = 5; int z1 = --x1; // z1=4; x1=4 Console.WriteLine($"{x1} - {z1}"); int x2 = 5; int z2 = x2--; // z2=5; x2=4 Console.WriteLine($"{x2} - {z2}");
При выполнении сразу нескольких арифметических операций следует учитывать порядок их выполнения. Приоритет операций от наивысшего к низшему:
Инкремент, декремент
Умножение, деление, получение остатка
Сложение, вычитание
Для изменения порядка следования операций применяются скобки.
Рассмотрим набор операций:
Int a = 3; int b = 5; int c = 40; int d = c---b*a; // a=3 b=5 c=39 d=25 Console.WriteLine($"a={a} b={b} c={c} d={d}");
Здесь мы имеем дело с тремя операциями: декремент, вычитание и умножение. Сначала выполняется декремент переменной c, затем умножение b*a, и в конце вычитание. То есть фактически набор операций выглядел так:
Int d = (c--)-(b*a);
Но с помощью скобок мы могли бы изменить порядок операций, например, следующим образом:
Int a = 3; int b = 5; int c = 40; int d = (c-(--b))*a; // a=3 b=4 c=40 d=108 Console.WriteLine($"a={a} b={b} c={c} d={d}");
Ассоциативность операторов
Как выше было отмечено, операции умножения и деления имеют один и тот же приоритет, но какой тогда результат будет в выражении:
Int x = 10 / 5 * 2;
Стоит нам трактовать это выражение как (10 / 5) * 2 или как 10 / (5 * 2) ? Ведь в зависимости от трактовки мы получим разные результаты.
Когда операции имеют один и тот же приоритет, порядок вычисления определяется ассоциативностью операторов. В зависимости от ассоциативности есть два типа операторов:
Левоассоциативные операторы, которые выполняются слева направо
Правоассоциативные операторы, которые выполняются справа налево
Все арифметические операторы (кроме префиксного инкремента и декремента) являются левоассоциативными, то есть выполняются слева направо. Поэтому выражение 10 / 5 * 2 необходимо трактовать как (10 / 5) * 2 , то есть результатом будет 4.
Последнее обновление: 19.06.2017
Отдельный набор операций представляет условные выражения. Такие операции возвращают логическое значение, то есть значение типа bool : true , если выражение истинно, и false , если выражение ложно. К подобным операциям относятся операции сравнения и логические операции.
Операции сравнения
В операциях сравнения сравниваются два операнда и возвращается значение типа bool - true , если выражение верно, и false , если выражение неверно.
Сравнивает два операнда на равенство. Если они равны, то операция возвращает true , если не равны, то возвращается false :
B; // false
Сравнивает два операнда и возвращает true, если операнды не равны, и false, если они равны.
Int a = 10; int b = 4; bool c = a != b; // true bool d = a!=10; // false
Операция "меньше чем". Возвращает true, если первый операнд меньше второго, и false, если первый операнд больше второго:
Int a = 10; int b = 4; bool c = a < b; // false
Операция "больше чем". Сравнивает два операнда и возвращает true, если первый операнд больше второго, иначе возвращает false:
Int a = 10; int b = 4; bool c = a > b; // true bool d = a > 25; // false
Операция "меньше или равно". Сравнивает два операнда и возвращает true, если первый операнд меньше или равен второму. Иначе возвращает false.
Int a = 10; int b = 4; bool c = a <= b; // false bool d = a <= 25; // true
Операция "больше или равно". Сравнивает два операнда и возвращает true, если первый операнд больше или равен второму, иначе возвращается false:
Int a = 10; int b = 4; bool c = a >= b; // true bool d = a >= 25; // false
Операции <, > <=, >= имеют больший приоритет, чем == и!=.
Логические операции
Также в C# определены логические операторы, которые также возвращают значение типа bool . В качестве операндов они принимают значения типа bool . Как правило, применяются к отношениям и объединяют несколько операций сравнения.
Операция логического сложения или логическое ИЛИ. Возвращает true, если хотя бы один из операндов возвращает true.
Bool x1 = (5 > 6) | (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается true bool x2 = (5 > 6) | (4 > 6); // 5 > 6 - false, 4 >
Операция логического умножения или логическое И. Возвращает true, если оба операнда одновременно равны true.
Bool x1 = (5 > 6) & (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается false bool x2 = (5 < 6) & (4 < 6); // 5 < 6 - true, 4 < 6 - true, поэтому возвращается true
Операция логического сложения. Возвращает true, если хотя бы один из операндов возвращает true.
Bool x1 = (5 > 6) || (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается true bool x2 = (5 > 6) || (4 > 6); // 5 > 6 - false, 4 > 6 - false, поэтому возвращается false
Операция логического умножения. Возвращает true, если оба операнда одновременно равны true.
Bool x1 = (5 > 6) && (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается false bool x2 = (5 < 6) && (4 < 6); // 5 < 6 - true, 4 > 6 - true, поэтому возвращается true
Операция логического отрицания. Производится над одним операндом и возвращает true, если операнд равен false. Если операнд равен true, то операция возвращает false:
Bool a = true; bool b = !a; // false
Операция исключающего ИЛИ. Возвращает true, если либо первый, либо второй операнд (но не одновременно) равны true, иначе возвращает false
Bool x5 = (5 > 6) ^ (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается true bool x6 = (50 > 6) ^ (4 / 2 < 3); // 50 > 6 - true, 4/2 < 3 - true, поэтому возвращается false
Здесь у нас две пары операций | и || (а также & и &&) выполняют похожие действия, однако же они не равнозначны.
В выражении z=x|y; будут вычисляться оба значения - x и y.
В выражении же z=x||y; сначала будет вычисляться значение x, и если оно равно true , то вычисление значения y уже смысла не имеет, так как у нас в любом случае уже z будет равно true . Значение y будет вычисляться только в том случае, если x равно false
То же самое касается пары операций &/&& . В выражении z=x&y; будут вычисляться оба значения - x и y.
В выражении же z=x&&y; сначала будет вычисляться значение x, и если оно равно false , то вычисление значения y уже смысла не имеет, так как у нас в любом случае уже z будет равно false . Значение y будет вычисляться только в том случае, если x равно true
Поэтому операции || и && более удобны в вычислениях, так как позволяют сократить время на вычисление значения выражения, и тем самым повышают производительность. А операции | и & больше подходят для выполнения поразрядных операций над числами.
Операция && имеет больший приоритет, чем операция ||. Так, в выражении true || true && false сначала выполняется подвыражение true && false .
В языке C# неявных преобразований к логическому типу нет даже для целых арифметических типов. Поэтому вполне корректная в языке C++ запись:
int
k
1
= 7;
if
(k
1)
Console
.
WriteLine
("
ok
!");
незаконна в программах на C#. На этапе трансляции возникнет ошибка, поскольку вычисляемое условие имеет типint , а неявное преобразование этого типа к типуbool отсутствует.
В языке C# более строгие правила действуют и для логических операций. Так, записьif (k 1 && (x > y )), корректная в языке C++, приводит к ошибке в
программах на C#, поскольку операция && определена только для операндов типаbool , а в данном выражении один из операндов имеет типint . В языке C# в данных ситуациях следует использовать записи:
if
(k
1>0)
if
((k
1>0)
&&
(x
>
y
))
Логические операции делятся на две категории: одни выполняются над логическими значениями операндов, другие осуществляют выполнение логической операции над битами операндов. По этой причине в C# существуют две унарные операции отрицания - логическое отрицание, заданное операцией «!», и побитовое отрицание, заданное операцией «~». Первая из них определена над операндом типаbool , вторая - над операндом целочисленного типа, начиная с типаint и выше(int , uint , long , ulong ). Результатом операции во втором случае является операнд, в котором каждый бит заменен его дополнением. Приведем пример:
///
<
summary
>
/// Логические
выражения
///
summary
>
public
void
Logic
() {
//операции
отрицания ~, !
bool
b1, b2;
b1
= 2*2
== 4;
b2
=
!b1;
//b2=
~b1;
uint
j1
=
7,
j2;
j2
=
~j1;
//j2
=
!j1;
int j4
=
7,
j5;
j5
=
~j4;
Console.WriteLine("uint
j2
=
" +
j2
+ "
int
j5
=
" +
j5);
}
//
Logic
В этом фрагменте закомментированы операторы, приводящие к ошибкам. В первом случае была сделана попытка применения операции побитового отрицания к выражению типаbool , во втором - логическое отрицание применялось к целочисленным данным. И то, и другое в C# незаконно. Обратите внимание на разную интерпретацию побитового отрицания для беззнаковых и знаковых целочисленных типов. Для переменныхj 5 иj 2 строка битов, задающая значение - одна и та же, но интерпретируется по-разному. Соответствующий вывод таков:
uint
j
2
= 4294967288
int
j
5
= -8.
Бинарные логические операции «&& - условное И» и «|| - условное ИЛИ» определены только над данными типаbool . Операции называются условными или краткими, поскольку, вычисление второго операнда зависит от уже вычисленного значения первого операнда. Ценность условных логических операций заключается в их эффективности по времени выполнения. Часто они позволяют вычислить логическое выражение, имеющее смысл, но в котором второй операнд не определен. Приведем в качестве примера классическую задачу поиска по образцу в массиве, когда разыскивается элемент с заданным значением (образец). Такой элемент в массиве может быть, а может и не быть. Вот типичное решение этой задачи в упрощенном виде, но передающем суть дела:
//
Условное
And
-
&&
int[
]
ar
= {
1, 2, 3 };
int search
= 7;
int i
= 0;
while ((i
<
ar.Length)
&&
(ar[i]
!=
search))
{
i++;
}
if (i
<
ar.Length)
Console.WriteLine("
Образец
найден
");
else
Console.WriteLine("
Образец
не
найден
");
Если значение переменнойsearch (образца) не совпадает ни с одним из значений элементов массиваar , то последняя проверка условия циклаwhile будет выполняться при значенииi , равномar . Length . В этом случае первый операнд получит значениеfalse , и, хотя второй операнд при этом не определен, цикл нормально завершит свою работу. Второй операнд не определен в последней проверке, поскольку индекс элемента массива выходит за допустимые пределы (в C# индексация элементов начинается с нуля).
Три бинарные побитовые операции - «& - AND» , « | - OR», «^ - XOR» используются двояко. Они определены как над целыми типами вышеint , так и над булевыми типами. В первом случае они используются как побитовые операции, во втором - как обычные логические операции. Иногда необходимо, чтобы оба операнда вычислялись в любом случае, тогда без этих операций не обойтись. Вот пример первого их использования:
//Логические
побитовые операции
And
,
Or
,
XOR
(&,|,^)
int
k2
=
7,
k3
=
5,
k4,
k5, k6;
k4
=
k2
&
k3;
k5
=
k2 |
k3;
k6
=
k2 ^
k3;
Console.WriteLine("k4
=
" +
k4
+ "
k5
=
" +
k5
+ "
k6
=
" +
k6);
Результаты вывода:
k 4 = 5 k 5 = 7 k 6 =2
Приведем пример поиска по образцу с использованием логического AND: i = 0;
search
=
ar;
while
((i
<
ar.Length)
&
(ar[i]
!=
search))
i++;
if (i
<
ar.Length)
Console.WriteLine("
Образец
найден
");
else
c
Console.WriteLine("
Образец
не
найден
");
В данном фрагменте гарантируется наличие образца поиска в массиве, и фрагмент будет успешно выполнен. В тех же случаях, когда массив не содержит элементаsearch , будет инициировано исключение. Содержательный смысл такой процедуры - появление исключения - может быть признаком ошибки в данных, что требует специальной обработки ситуации.