Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C# / C#Лаб1 / ЛабРабота2.doc
Скачиваний:
35
Добавлен:
31.05.2015
Размер:
1.66 Mб
Скачать

Операции и их старшинство

Операции в C#, их приоритет и порядок унаследованы из языка C++.

При вычислении выражения определяется его значение и тип по типам операндов, входящих в выражение.

В табл. 3 операции перечислены по строкам в порядке убывания приоритетов.

Таблица 3

Прио-ритет

Категория

Операции

Порядок

0

Первичные

(expr) x.y f(x) a[x] x++ x-- new sizeof(t) typeof(t) checked(expr) unchecked(expr)

Слева направо

1

Унарные

+ - ! ~ ++x --x (T)x

-“-

2

Мультипликативные (Умножение)

* / %

-“-

3

Аддитивные (Сложение)

+ -

-“-

4

Сдвиг

<< >>

-“-

5

Отношения, проверка типов

< > <= >= is as

-“-

6

Эквивалентность

== !=

-“-

7

Логическое

&

-“-

8

Логическое исключающее ИЛИ (XOR)

^

-“-

9

Логическое ИЛИ (OR)

|

-“-

10

Условное И

&&

-“-

11

Условное ИЛИ

||

-“-

12

Условное выражение

? :

Справа налево

13

Присваивание

= *= /= %= += -= <<= >>= &= ^= |=

-“-

Операции checked и unchecked включают и выключают проверку преобразований арифметического типа в выражениях, которым они предшествуют.

Аналогично языку С++, операции "увеличить на единицу" и "уменьшить на единицу" могут быть префиксными и постфиксными. К высшему приоритету относятся постфиксные операции (x++ и x--).

Для префиксных (++x, --x) операций результатом их выполнения является измененное значение x, постфиксные операции возвращают в качестве результата значение x до изменения.

Операции могут иметь побочный эффект.

int var1=5, var2=3, var3;

var3=var1++*--var2; //var3=10

Как и в С++, операция sizeof возвращает размер значимого типа в байтах. Она выполняется только в небезопасных блоках: проект должен быть скомпилирован с включенным свойством /unsafe.

Операция typeof возвращает тип операнда, к которому она применена. Операндом может быть имя встроенного или Пользовательского класса. Возвращаемый результат имеет тип Type.

Для экземпляра класса можно вызвать метод GetType(), наследуемый всеми классами, и получить тот же результат, что дает typeof с именем данного класса.

Пример использования вызова операции typeof:

t = typeof(Class1);

Console.WriteLine("Тип класса Class1: {0}", t);

t = typeof(Testing);

Console.WriteLine("Тип класса Testing: {0}", t);

В языке C# имеются обычные для всех языков арифметические операции - "+, -, *, /, %". Все они перегружены.

Операции "+" и "-" могут быть унарными и бинарными.

Операция деления "/" над целыми типами выполняет деление нацело, для типов с плавающей и фиксированной точкой - обычное деление.

Операция "%" определена над всеми арифметическими типами и возвращает остаток от деления нацело. Тип результата зависит от типов операндов.

Пример вычислений с арифметическими типами:

public void Ariphmetica() {

int n = 7,m =3, p,q;

p= n/m; q= p*m + n%m;

if (q==n) Console.WriteLine("q=n");

else Console.WriteLine("q!=n");

double x=7, y =3, u,v,w;

u = x/y; v= u*y;

w= x%y;

if (v==x) Console.WriteLine("v=x");

else Console.WriteLine("v!=x");

decimal d1=7, d2 =3, d3,d4,d5;

d3 = d1/d2; d4= d3*d2;

d5= d1%d2;

if (d4==d1) Console.WriteLine("d4=d1");

else Console.WriteLine("d4!=d1"); }

При проведении вычислений в двух первых случаях проверяемое условие оказалось истинным, в третьем - ложным. Для целых типов можно исходить из того, что равенство n = n/m*m + n%m истинно.

Для типов с плавающей точкой выполнение точное равенство x = x/y*y не гарантируется.

Операций отношения всего операций 6: ==, !=, <, >, <=, >= . Они имеют аналогичный смысл, что и для других языков программирования.

Операции сдвига вправо ">>" и сдвига влево "<<" особенно полезны, если данные рассматриваются как строка битов. Результатом операции является сдвиг строки битов влево или вправо на K разрядов. В применении к целым положительным числам сдвиг вправо равносилен делению нацело на 2K, а сдвиг влево - умножению на 2K.

Для отрицательных чисел сдвиг влево и деление дают разные результаты, отличающиеся на единицу.

Операции сдвига определены только для некоторых целочисленных типов - int, uint, long, ulong. Величина сдвига должна иметь тип int. Пример выполнения операций сдвига:

int result, v1=4, v2=2 ;

result=v1>>v2; // result=1

result=v1<<v2; // result=16

public void Shift()

{

int n = 17,m =3, p,q;

p= n>>2; q = m<<2;

Console.WriteLine("n= " + n + "; m= " + m + "; p=n>>2 = "+p

+ "; q=m<<2 " + q);

long x=-75, y =-333, u,v,w;

u = x>>2; v = y<<2; w = x/4;

Console.WriteLine("x= " + x + "; y= " + y + "; u=x>>2 = "+u

+ "; v=y<<2 " + v + "; w = x/4 = " + w);

}

Рис. 10. Операции сдвига

В языке C++ практически для всех типов существует неявное преобразование в логический тип. Все, что отлично от 0, является истинной, 0 - это ложь.

В языке C# неявных преобразований к логическому типу bool нет.

Так же, как и в языке C++, логические операции делятся на две категории:

- выполняемые над логическими значениями операндов,

- операции над битами операндов.

Пример:

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); }

Ошибки следующие: в первом случае сделана попытка применения операции побитового отрицания к выражению типа bool, во втором - логическое отрицание применялось к целочисленным данным.

Для переменных j5 и j2 строка битов, задающая значение - одна и та же, но интерпретируется по-разному.

Поэтому будет выведено:

uint j2 = 4294967288 int j5 = -8

//Логические побитовые операции And, Or, XOR (&,|,^)

int result, v1=4, v2=5 ;

result=v1&v2; // result=4

result=v1|v2; // result=5

result=v1^v2; // result=1

result=~v1; // result=-5

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);

Результаты вывода:

k4 = 5 k5 = 7 k6 =2

Бинарные логические операции "&& - условное И" и "|| - условное ИЛИ" определены только над данными типа bool.

Операции называются условными или краткими, поскольку, будет ли вычисляться второй операнд, зависит от уже вычисленного значения первого операнда.

В операции "&&", если первый операнд равен значению false, то второй операнд не вычисляется и результат операции равен false.

Аналогично, в операции "||", если первый операнд равен значению true, то второй операнд не вычисляется и результат операции равен true.

Поэтому полезным оказывается такой пример:

//Условное 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, и, хотя второй операнд при этом не определен, цикл нормально завершит свою работу.

Второй операнд не определен в последней проверке, поскольку индекс элемента массива выходит за допустимые пределы.

Бинарные побитовые операции - "& - AND " , "| - OR ", "^ - XOR" определены как над целыми типами выше int, так и над булевыми типами.

Теперь пример поиска по образцу с использованием логического AND:

i=0; search = ar[ar.Length - 1];

while ((i < ar.Length) & (ar[i]!= search)) i++;

if(i<ar.Length) Console.WriteLine("Образец найден");

else Console.WriteLine("Образец не найден");

В этом фрагменте гарантируется наличие образца поиска в массиве, и фрагмент будет успешно выполнен. В случаях, когда массив не содержит элемента search, выбрасывается исключение.

В C#, как и в C++, разрешены условные выражения () ? :

int a = 7, b= 9, max;

max= (a>b) ? a:b;

Console.WriteLine("a = " + a + "; b= " + b +"; max(a,b) = " + max);

Условное выражение начинается с условия, заключенного в круглые скобки, после которого следует знак вопроса и пара выражений, разделенных двоеточием.

Условием является выражение типа bool. Если оно истинно, то выбирается первое выражение, в противном случае результатом является значение второго выражения. В примере переменная max получит значение 9.

Операция приведения к типу имеет следующий синтаксис:

(type) <унарное выражение>

Она задает явное преобразование типа, определенного выражением, к типу, указанному в скобках. Чтобы операция была успешной, необходимо, чтобы такое явное преобразование существовало.

Существуют явные преобразования внутри арифметического типа. При определении пользовательских типов для них могут быть заданы явные преобразования в другие типы.

Пример:

int p;

p = (int)x;

//b = (bool)x; ошибка

Существует 2 способа преобразования типов.

Неявное – преобразование типа А в тип В возможно при любых обстоятельствах, их правила преобразования просты, компилятор сам справится с этой работой.

Явное – преобразование типа А в тип В возможно лишь при определенных обстоятельствах, при этом требуются дополнительные действия.

В табл. 4 записаны допустимые неявные преобразования для численных типов.

При явном преобразовании типа необходимо записать

(<требуемый тип >)<имя>

Таблица 4

Тип

Можно безопасно преобразовать в

byte

short, ushort, int, uint, long, ulong, float, double, decimal

sbyte

short, int, long, float, double, decimal

short

int, long, float, double, decimal

ushort

int, uint, long, ulong, float, double, decimal

int

long, float, double, decimal

uint

long, ulong, float, double, decimal

long

float, double, decimal

ulong

float, double, decimal

float

double

char

ushort, int, uint, long, ulong, float, double, decimal

Такая запись возможна только в некоторых ситуациях. Для типов, мало похожих друг на друга, или вовсе не имеющих ничего общего, такое преобразование, будет неопределено.

byte destVar;

short sourceVar=281;

destVar=(byte)sourceVar;

Console.WriteLine(“sourceVar={0}”, sourceVar); // 281

Console.WriteLine(“destVar={0}”, destVar); // 25

Произошло это в связи с тем, что потерян самый левый бит исходного значения:

281 =100011001

25 =000011001

А максимальное значение типа byte равно 255 ( 011111111).

Можно проверить переполнение с помощью слов checked и unchecked:

checked(<выражение>)

unchecked(<выражение>)

Если добавить эту проверку

byte destVar; short sourceVar=281;

destVar=checked((byte)sourceVar);

Console.WriteLine("sourceVar={0}", sourceVar);

Console.WriteLine("destVar={0}", destVar);

то процесс выполнения будет прерван и появится сообщение об ошибке

Рис. 11. Произошло переполнение

Если вместо checked записать unchecked

byte destVar;

short sourceVar=281;

destVar=unchecked((byte)sourceVar);

Console.WriteLine("sourceVar={0}", sourceVar);

Console.WriteLine("destVar={0}", destVar);

то программа выполнится с первоначальным результатом.

Для явного преобразования используются методы класса Convert (табл. 5).

Таблица 5

Команда

Результат: преобразовано в

Convert.ToBoolean(val)

bool

Convert.ToByte(val)

byte

Convert.ToChar(val)

char

Convert.ToDecimal(val)

decimal

Convert.ToDouble(val)

double

Convert.ToInt16(val)

short

Convert.ToInt32(val)

int

Convert.ToInt64(val)

long

Convert.ToSbyte(val)

sbyte

Convert.ToSingle(val)

float

Convert.ToString(val)

string

Convert.ToUInt16(val)

ushort

Convert.ToUInt32(val)

uint

Convert.ToUInt64(val)

ulong

Имена типов взяты из System .NET Framework, благодаря чему их можно использовать из любых других языков, совместимых с .NET.

При таких преобразованиях всегда контролируется переполнение, не смотря на наличие checked, unchecked и установок для проекта.

Пример

short shortResult, shortVal=4;

int integerVal=67;

long longResult;

float floatVal=10.5F;

double doubleResult, doubleVal=99.999;

string stringResult, stringVal="17";

bool boolVal=true;

Console.WriteLine("Примеры преобразования типов\n");

doubleResult = floatVal*shortVal;

Console.WriteLine("Неявное, ->double: {0} * {1} -> {2}",

floatVal,shortVal,doubleResult);

shortResult = (short)floatVal;

Console.WriteLine("Явное, -> short: {0} -> {1}",floatVal,shortResult);

stringResult = Convert.ToString(boolVal)+

Convert.ToString(doubleVal);

Console.WriteLine("Явное, ->string: \"{0}\"{1}\" -> {2}",

boolVal,doubleVal,stringResult);

stringResult = stringVal+ floatVal;

Console.WriteLine("Неявное, ->string: \"{0}\"+ {1} -> {2}",

stringVal,floatVal,stringResult);

longResult=integerVal + Convert.ToInt64(stringVal);

Console.WriteLine("Смешенное, -> long: {0} + {1} -> {2}",

integerVal,stringVal,longResult);

Рис. 12. Результаты преобразования типов

Соседние файлы в папке C#Лаб1