Файл: 1_C#_Введение_в_программирование_Уч_пособ_(Марченко-2005).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 11.12.2025

Просмотров: 1327

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

с обязательным разделителем ‘:’ обеспечивают реализацию принципа наследования и будут обсуждаться позже.

Тело класса в объявлении ограничивается парой разделителей ‘{‘, ‘}’, между которыми располагаются объявления данных-членов и методов класса.

Следующий пример является демонстрирует использование основных элементов объявления структуры. При объявлении класса допускается лишь один спецификатор – public (здесь он опущен). Отсутствие спецификаторов доступа в объявлениях членов структуры (класса) эквивалентно явному указанию спецификаторов private.

// Указание на используемые пространства имён. using System;

using System.Drawing;

namespace qwe // Объявление собственного пространства имён. Начало.

{

//Начало объявления структуры struct S1

{// Тело структуры - НАЧАЛО

//Объявление данных-членов. private Point p;

//protected int qwe; // Спецификатор protected в объявлении членов

//структуры недопустим.

//Структура не может иметь конструктора без параметров.

public S1(int x, int y)

{

p = new Point(10,10);

}

//Объявление методов.

//Статический метод. Точка входа. static void Main(string[] args)

{

//Тело метода. Здесь обычно располагается программный код,

//определяющий функциональность класса.

}

}// Тело структуры - КОНЕЦ } // Объявление собственного пространства имён. Конец.

Литералы. Представление значений

В программах на языках высокого уровня (C# в том числе) литералами называют последовательности входящих в алфавит языка программирования символов, обеспечивающих явное представление значений, которые используются для обозначения начальных значений в объявлении членов классов, переменных и констант в методах класса.

Различаются литералы арифметические (разных типов), логические, символьные (включая Escape-последовательности), строковые.

Арифметические литералы

Арифметические литералы кодируют значения различных (арифметических) типов. Тип арифметического литерала определяется следующими интуитивно понятными внешними признаками:

стандартным внешним видом. Значение целочисленного типа обычно кодируется интуитивно понятной последовательностью символов ‘1’,…, ‘9’, ‘0’. Значение плавающего типа также предполагает стандартный вид (точка-разделитель между целой и дробной частью, либо научная или экспоненциальная нотация – 1.2500E+052). Шестнадцатеричное представление целочисленного значения кодируется шестнадцатеричным литералом, состоящим из символов ‘0’,…,‘9’, а

также ‘a’,…, ‘f’, либо ‘A’,…,‘F’ с префиксом ‘0x’,

собственно значением. 32768 никак не может быть типа short,

дополнительным префиксом. Префиксы l,L соответствуют типу long, ul,UL – unsigned long, f,F – float, d,D – decimal. Значения типа double кодируются без префикса.

14


Логические литералы

К логическим литералам относятся следующие последовательности символов: true и false. Больше логических литералов в C# нет.

Символьные литералы

заключённые в одинарные кавычки вводимые с клавиатуры одиночные символы: ‘X’, ‘p’, ‘Q’, ‘7’,

целочисленные значения в диапазоне от 0 до 65535, перед которыми располагается конструкция вида (char) – операция явного приведения к типу char: (char)34 – ‘”’, (char)44 – ‘,’, (char)7541 – что здесь будет – не ясно.

Символьные escape-последовательности

Следующие заключённые в одинарные кавычки последовательности символов являются Escape-последовательностями. Эта категория литералов используется для создания дополнительных эффектов (звонок), простого форматирования выводимой информации и кодирования символов при выводе и сравнении (в выражениях сравнения).

Escape-последовательность

Описание

\a

Предупреждение (звонок)

\b

Возврат на одну позицию

\f

Переход на новую страницу

\n

Переход на новую строку

\r

Возврат каретки

\t

Горизонтальная табуляция

\v

Вертикальная табуляция

\0

Ноль

\’

Одинарная кавычка

\”

Двойная кавычка

\\

Обратная косая черта

Строковые литералы

Это последовательность символов и символьных escape-последовательностей, заключённых в двойные кавычки.

A verbatim string – строковый литерал, интерпретируемый компилятором так, как он записан. Escape-последовательности воспринимаются строго как последовательности символов.

Verbatim string представляется при помощи символа @, располагаемого непосредственно перед строковым литералом, заключённым в парные двойные кавычки. Представление двойных кавычек в Verbatim string обеспечивается их дублированием. Пара литералов (второй - Verbatim string):

…“c:\\My Documents\\sample.txt”… …@“c:\My Documents\sample.txt”…

имеют одно и то же значение: c:\My Documents\sample.txt

Представление двойных кавычек внутри Verbatim string достигается за счёт их дублирования:

…@“““Focus”””

имеет значение

“Focus”

Строковые литералы являются литералами типа string.

Операции и выражения

Для каждого определённого в C# типа существует собственный набор операций, определённых на множестве значений этого типа.

15


Эти операции определяют диапазон возможных преобразований, которые могут быть осуществлены над элементами множеств значений типа. Несмотря на специфику разных типов, в C# существует общее основание для классификации соответствующих множеств операций. Каждая операция является членом определённого подмножества операций и имеет собственное графическое представление.

Общие характеристики используемых в C# операций представлены ниже.

Категории операций

 

 

Операции

Arithmetic

 

 

 

+ - * / %

Логические (boolean и побитовые)

 

& | ^ ! ~ && ||

Строковые (конкатенаторы)

 

+

Increment, decrement

 

 

++ --

Сдвига

 

 

 

>> <<

Сравнения

 

 

 

== != < > <= >=

Присвоения

 

 

 

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

Member access

 

 

.

Индексации

 

 

 

[]

Cast (приведение типа)

 

 

()

Conditional (трёхоперандная)

 

?:

Delegate concatenation and removal

 

+ -

Создания объекта

 

 

new()

Type information

 

 

is sizeof typeof

Overflow

exception

control

(управление

checked unchecked

исключениями)

 

 

* -> [] &

Indirection and Address (неуправляемый код)

Так вот на основе элементарных (первичных) выражений с использованием этих самых операций и дополнительных разделителей в виде открывающихся и закрывающихся скобочек формируются выражения всё более сложной структуры. Кроме того, при создании, трансляции, а, главное, на стадии выполнения (определения значения выражения) учитываются следующие обстоятельства:

приоритет операций,

типы операндов и приведение типов.

Приоритет операций

Приоритет Операции

1() [] . (постфикс)++ (постфикс)-- new sizeof typeof unchecked

2! ~ (имя типа) +(унарный) -(унарный) ++(префикс) --(префикс)

3* / %

4+ -

5<< >>

6< > <= => is

7== !=

8&

9^

10|

11&&

12||

13?:

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

Приведение типов

В одном выражении могут быть сгруппированы операнды различных типов. Однако возможность смешения в одном выражении операндов различных типов связана с определёнными проблемами на этапе выполнения программы и в ряде случаев требует дополнительного внимания со стороны программиста.

Прежде всего, КАК производится это преобразование. Иногда оно производится абсолютно незаметно и не требует дополнительных усилий со стороны программиста. Все необходимые преобразования осуществляется автоматически в ходе выполнения программы. Такие преобразования называются неявными. Однако чаще программист вынужден явным образом указывать необходимость преобразования, используя выражения приведения типа или обращаясь к специальным методам преобразования, определённым в классе System.Convert.

16


Приведение типов – один из аспектов безопасности языка. Всё должно быть устроено таким образом, чтобы логика преобразования значений одного типа к другому типу была бы понятной, а результаты этих преобразований предсказуемы.

Используемые в программе типы характеризуются собственными диапазонами значений, которые определяются свойствами типов. В том числе и размером области памяти, предназначенной для кодирования значений соответствующего типа. При этом области значений различных типов пересекаются. Многие значения можно выразить более чем одним типом. Например, значение 4 можно представить как целое число или как число с плавающей точкой.

Преобразование типа создает значение нового типа, эквивалентное значению старого типа, однако при этом не обязательно сохраняется идентичность (или точные значения) двух объектов.

Различаются:

Расширяющее преобразование – значение одного типа преобразуется к значению другого типа, которое имеет такой же или больший размер. Например, значение, представленное в виде 32-разрядного целого числа со знаком, может быть преобразовано в 64-разрядное целое число со знаком. Расширяющее преобразование считается безопасным, поскольку исходная информация при таком преобразовании не искажается.

Тип

Возможно безопасное преобразование к типу…

Byte

UInt16, Int16,

UInt32, Int32, UInt64,

Int64, Single, Double, Decimal

SByte

Int16, Int32, Int64, Single, Double, Decimal

Int16

Int32, Int64, Single, Double, Decimal

 

UInt16

UInt32, Int32,

UInt64, Int64, Single,

Double, Decimal

Char

UInt16, UInt32, Int32, UInt64, Int64,

Single, Double, Decimal

Int32

Int64, Double,

Decimal

 

UInt32

Int64, Double,

Decimal

 

Int64

Decimal

 

 

UInt64

Decimal

 

 

Single

Double

 

 

Некоторые расширяющие преобразования типа могут привести к потере точности. Следующая таблица описывает варианты преобразований, которые иногда приводят к потере информации.

Тип

Возможна потеря точности при преобразовании к типу…

Int32

Single

UInt32

Single

Int64

Single, Double

UInt64

Single, Double

Decimal

Single, Double

Сужающее преобразование - значение одного типа преобразуется к значению другого типа, которое имеет меньший размер (из 64-разрядного в 32-разрядное). Такое преобразование потенциально опасно потерей значения.

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

PositiveInfinity или NegativeInfinity.

При этом значение PositiveInfinity интерпретируется как результат деления положительного числа на ноль, а значение NegativeInfinity интерпретируется как результат деления отрицательного числа на ноль.

Если сужающее преобразование обеспечивается методами класса System.Convert, то потеря информации сопровождается генерацией исключения (об этом позже).

Тип

Возможна потеря значения и генерация исключения при преобразовании в:

Byte

Sbyte

 

SByte

Byte, UInt16, UInt32, UInt64

Int16

Byte, SByte, UInt16

 

UInt16

Byte, SByte, Int16

 

Int32

Byte, SByte, Int16,

UInt16, UInt32

UInt32

Byte, SByte, Int16,

UInt16, Int32

Int64

Byte, SByte, Int16,

UInt16, Int32, UInt32, UInt64

UInt64

Byte, SByte, Int16,

UInt16, Int32, UInt32, Int64

Decimal

Byte, SByte, Int16,

UInt16, Int32, UInt32, Int64, UInt64

17


Single

Byte,

SByte,

Int16,

UInt16,

Int32,

UInt32,

Int64,

UInt64

Double

Byte,

SByte,

Int16,

UInt16,

Int32,

UInt32,

Int64,

UInt64

Особенности выполнения арифметических операций

Особенности выполнения операций над целочисленными

операндами и операндами

с плавающей точкой связаны с особенностями выполнения

арифметических операций

ис ограниченной точностью переменных типа float и double. Представление величин:

float – 7 значащих цифр. double – 16 значащих цифр.

1000000*100000==1000000000000, но максимально допустимое положительное значение для типа System.Int32 составляет 2147483647. В результате переполнения получается неверный результат -727379968.

Ограниченная точность значений типа System.Single проявляется при присвоении значений переменной типа System.Double. Приводимый ниже простой программный код иллюстрирует некоторые особенности арифметики .NET.

using System;

class Class1

{

const double epsilon = 0.00001D; static void Main(string[] args)

{

int valI = 1000000, resI; resI = (valI*valI)/valI;

// -727379968/1000000 == -727

Console.WriteLine("The result of action (1000000*1000000/1000000) is {0}", resI);

float valF00 = 0.2F, resF; double valD00 = 0.2D, resD;

// Тест на количество значащих цифр для значений типа double и float. resD = 12345678901234567890; Console.WriteLine(">>>>> {0:F10}",resD); resF = (float)resD; Console.WriteLine(">>>>> {0:F10}",resF);

resD = (double)(valF00 + valF00); // 0.400000005960464 if (resD == 0.4D) Console.WriteLine("Yes! {0}",resD); else Console.WriteLine("No! {0}",resD);

resF = valF00*5.0F; resD = valD00*5.0D;

resF = (float)valD00*5.0F;

resD = valF00*5.0D; //1.0000000149011612

if (resD == 1.0D) Console.WriteLine("Yes! {0}",resD);

else

Console.WriteLine("No! {0}",resD);

resF = valF00*5.0F;

resD

= valF00*5.0F; //1.0000000149011612

if

(resD.Equals(1.0D))

Console.WriteLine("Yes! {0}",resD);

else

Console.WriteLine("No! {0}",resD);

if

(Math.Abs(resD - 1.0D) < epsilon)

Console.WriteLine("Yes! {0:F7}, {1:F7}",resD - 1.0D, epsilon);

else

Console.WriteLine("No! {0:F7}, {1:F7}",resD - 1.0D, epsilon);

}

}

Особенности арифметики с плавающей точкой

Если переменной типа float присвоить величину x из интервала

-1.5E-45 < x < 1.5E-45 (x != 0),

18