Министерство образования Российской Федерации Нижегородский государственный университет им. Н.И. Лобачевского Физический факультет Кафедра информационных технологий в физических исследованиях Язык программирования С# Методическое пособие Нижний Новгород 2005 Язык программирования С# Нижний Новгород 2005 УДК 681.3 Минеев С.А., Пряничников А.В., Кузьмина И.В. Язык С#. Методическое пособие - Н.Новгород: ННГУ, 2005. - 107 с. В пособии содержится описание семантики и синтаксиса языка программирования общего назначения C# . Приведены описания часто применяемых классов стандартных библиотек. Cоставители: Минеев С.А.- ст. преп. кафедры ИТФИ, к.ф.-м. н; Пряничников А.В. – м.н.с НИФТИ ННГУ; Кузьмина И.В. – м.н.с. НИФТИ ННГУ. Рецензент: Будников Д.Н. – инженер по программным технологиям фирмы “Intel”. Нижегородский государственный университет им. Н.И. Лобачевского, 2005 ВВЕДЕНИЕ C# (читается как "Си шарп") является объектно-ориентированным языком программирования, разработанным для создания программ на базе платформы Microsoft .NET. Он во многом похож на другие объектно-ориентированные языки общего назначения, такие как C++ и Java, но имеет и свои отличительные особенности. 1. Элементы языка 1.1 Комментарии В C# используется два типа комментирования: комментирование блока текста, комментирование строки. Чтобы вставить блочный (многострочный комментарий), текст комментария обрамляется символами /* в начале и */ в конце: /* Эта переменная хранит количество элементов. */ int count; Блочные комментарии не могут быть вложенными: последовательность символов */ завершает все открытые комментарии. первая Также можно закомментировать строку текста (всю или часть). Для этого используются символы //, весь текст до конца текущей строки становится комментарием. int count; // Эта переменная хранит количество элементов 3 Однострочные комментарии имеют больший приоритет, т.е. символы //* комментируют текст до конца строки, не требуя завершающих символов */. 1.2 Идентификаторы Представляют собой последовательность букв, подчеркиваний или цифр, начинающуюся с буквы или подчеркивания. Различают регистр, то есть foo — это не то же самое, что Foo. Идентификаторы могут иметь произвольную длину (однако, некоторые реализации имеют ограничения). Допускаются национальные символы. 4 1.3 Ключевые слова Таб 2.1 Ключевые слова, зарезервированные языком Abstract class event if new readonly As const explicit implicit null ref Base continue extern in object return Bool decimal false int operator sbyte Break default finally interface out sealed Byte delegate fixed internal override short Case do float is params sizeof Catch double for lock private stackalloc Char else foreach long protected static Checked enum goto namespace public string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while 1.4 Константы 1.4.1 Целые знаковые Десятичные: необязательный знак, за которым следует ненулевая цифра, за которой, в свою очередь, следует произвольное число цифр. 23, –42, 3L, +1991 // плюс допустим, но необязателен Имеют тип int, если значение константы не превышает максимального допустимого значения для числа типа int, в противном случае имеет тип long. Тип для длинных целых (long) может быть явно указан с помощью постфикса L. 1.4.2 Целые беззнаковые Неотрицательные целые (uint) или длинные целые (ulong) константы. Десятичные: целые или длинные целые константы без знака с постфиксом U или u. 23U, 42u, +1991UL Восьмеричные: ноль, за которым следует произвольное количество цифр в диапазоне от 0 до 7. 027, 052, 03707 Шестнадцатеричные: префикс 0х или 0Х, за которым следует произвольное количество цифр или букв в диапазоне от а до f или от А до F. 5 0х17, 0х2а, 0Х7С7 Целые беззнаковые имеют тип unsigned int, если значение константы не превышает максимального допустимого значения для типа unsigned int, в противном случае имеют тип unsigned long. 1.4.3 С плавающей точкой Язык C# поддерживает два типа с плавающей точкой: float и double. Тип float имеет точность в 7 знаков, double — 15-16. Значения величин с плавающей точкой имеют целую часть, десятичную точку, дробную часть, символ e или E и экспоненту со знаком или без него. Но могут и не иметь целой или дробной части, а также не иметь десятичной точки или экспоненты. 3.14159, 3Е8, 1.0, .2, 1.602е–19 По умолчанию значения имеют тип double, за исключением случаев, когда они оканчиваются символом F или f (тип float). 23F, 4.2f, 1991F // float 1.4.4 Символьные Чаще всего представляют собой отдельный символ, заключенный в одиночные кавычки. Имеют тип char. 'm', '7', '+' Имеют числовые значения, которые равны значениям машинных кодов соответствующих символов. 'А' в кодировке ASCII имеет значение 65 Для представления определенных символов используются управляющие последовательности, начинающиеся на обратную косую черту. Нулевой символ Тревога (звонок) Новая строка Горизонтальная табуляция Вертикальная табуляция Забой Возврат каретки Прогон формата Обратная косая черта NULL BEL NL (LF) HT VT BS CR FF \ '\0' '\a' '\n' '\t' '\v' '\b' '\r' '\f' '\\' 6 Одиночная кавычка Двойная кавычка Битовая маска1 Битовая маска ‘ “ Oddd Oxddd '\'' '\"' '\ddd' '\xddd' 1.4.5 Строковые Ноль и более символов, окруженные двойными кавычками "m", "C++", "Частота" Имеют тип string. Строковые значения могут быть записаны в нескольких строках кода. Для соединения (конкатенации) строк используется перегруженный оператор сложения (+). string заключение = ”Неисправны” + “ выпускной клапан и ” + “барометр”; // Ниже приведены две одинаковые строки приветствие_1 = ”Здравствуй, мир!”; приветствие_2 = ”Здравствуй,” + “ мир!”; 1.5 Выражения Выражения объединяют переменные, константы, вызовы функций для получения новых значений. Например, выражениями являются следующие операции: i = 0; c++; x = a * a + b * b; f = GetFrequency(y); 1.6 Операции При описании операций будут использоваться следующие сокращения. e Произвольное выражение. v Любое выражение, которое может принимать значение. i Целое или символ. Допускаются битовые маски, которые могут быть заданы последовательностью шестнадцатеричных или восьмеричных цифр содержащих от одной до трех цифр. 1 7 a Арифметическое (целое, символ или с плавающей точкой). s Класс. m Член класса. Эти сокращения могут комбинироваться. Например, ie — это выражение целого типа. 1.6.1 Арифметические операции ae+ae Сумма ae–ae Разность +ae Унарный плюс –ae Унарный минус ae*ae Произведение ae/ae Частное ie%ie Остаток от деления2 1.6.2 Логические операции e1 & e2 И. Значение e2 вычисляется вне зависимости от значения e1. e1 && e2 И. Значение e2 вычисляется только, если е1 истинно. !е НЕ (отрицание). e1 | e2 ИЛИ. Значение e2 вычисляется вне зависимости от значения e1. e1 || e2 ИЛИ. Значение e2 вычисляется только, если е1 ложно. 1.6.3 Операции отношения Возвращают булево значение в соответствии с отношением своих аргументов. == Равно. != Не равно. < Меньше. <= Меньше или равно. > Больше >= Больше или равно. 1.6.4 Операции присваивания 2 Знак результата не определен, если один из операндов или оба операнда имеют отрицательное значение. 8 v=e Присваивает v значение е v+=e Эквивалентно v=v+e v–=e Эквивалентно v=v–e v*=e Эквивалентно v=v*e v/=e Эквивалентно v=v/e Допускается множественное присваивание, выполняемое операции. При этом присваивания выполняются справа налево. в одной 1.6.5 Операции инкремента и декремента Операции инкремента и декремента соответственно увеличивают и уменьшают на единицу значение переменной. Префиксный инкремент (увеличение iv на единицу). Результатом выражения является увеличенное на единицу значение iv. Постфиксный инкремент (увеличение iv на единицу). Результатом является значение iv до увеличения на единицу. Префиксный декремент (уменьшение iv на единицу). Результатом выражения является уменьшенное на единицу значение iv. Постфиксный декремент (уменьшение iv на единицу). Результатом является значение iv до уменьшения на единицу. ++iv iv++ --iv iv-- int a = 5, b, c; // Постфиксный инкремент b = a++; // Выражение аналогично следующему: // b = a; a++; Console.WriteLine("a = {0}, b = {1}", a, b); // Префиксный инкремент c = ++b; // Выражение аналогично следующему: // b++; c = b; Console.WriteLine("b = {0}, c = {1}", b, c); Результат выполнения: a = 6, b = 5 b = 6, c = 6 1.6.6 Операции с массивами pe[ie] Доступ к элементу с индексом ie массива ре. 9 1.6.7 Операции класса Доступ к полю класса. sv.m 1.6.8 Побитовые операции ~ie Дополнение до единицы (побитовое НЕ). iel << ie2 Сдвиг iel влево на ie2 бит. В освобождающиеся биты записываются нули. iel >>ie2 iel & ie2 Сдвиг iel вправо на ie2 бит. В освобождающиеся биты записываются нули, если iel имеет беззнаковый тип, либо неопределенное значение, если iel имеет знаковый тип. Побитовое И. iel | ie2 Побитовое ИЛИ. iel ^ ie2 Побитовое исключающее ИЛИ. char letterA = 'A'; ‘A’ char letterB = 'b'; const char mask = (char)0x20; смены регистра char lower = (char)(letterA | char upper = (char)(letterB & символ ‘B’ // Двоичное 01000001, символ // 01100010, символ ‘ b’ // 00100000, маска для mask);// ~mask); 01100001, символ ‘a’ // 01000010, 1.6.9 Прочие операции el ? e2 : e3 Тернарный оператор. Если выполняется условие el, то результатом операции является значение е2. В противном случае результатом является значение e3. sizeof (Тип) Число байтов для типа Тип. typeof (Тип) Используется для получения объекта System.Type для типа Тип. as Применяется при приведении типов. is Используется для проверки совместимости одного типа данных с другим. checked Проверяет, не выходит ли результат арифметических операций за пределы допустимых значений (только для целочисленных типов). Применяется для отмены контроля допустимых значений вычисляемых арифметических выражений (только для целочисленных типов). unchecked 10 1.6.10 Операции распределения памяти Выделяет память для типа type и возвращает ссылку на экземпляр данного типа. При отсутствии достаточного объема памяти генерируется исключение System.OutOfMemoryException. new type Выделяет память для массива из ie элементов типа type и возвращает ссылку на массив. При этом конструктор вызывается для каждого элемента. При отсутствии достаточного объема памяти генерируется исключение System.OutOfMemoryException. new type [ie] new type [] { Выделяет память для массива типа type и инициализирует элементы значение_1, значениями из списка. Возвращает ссылку на массив. значение_2, … } 1.6.11 Приоритет и порядок выполнения операций В таблице, приводимой ниже, операции расположены в порядке убывания приоритета. Операции с одинаковым приоритетом объединены в группы. Таб.2.2 Полный набор операторов С# Категория Операторы Первостепенные (первичные) x.y, f(x), a[x], x++, x--, new, typeof, checked, unchecked Унарные +, –, !, ~, ++x, --x, (T)x Мультипликативные *, / , % Аддитивные +,– Операторы сдвига << , >> Операторы отношения и проверки типов <, >, <= , >= , is, as Операторы равенства ==, != Логическое И (AND) & Логическое исключающее ИЛИ (XOR) ^ Логическое ИЛИ (OR) | Условное И (AND) && Условное ИЛИ (OR) || Операторы проверки ?: Операторы присваивания =, *=, /=, %=, +=, –=, <<=, >>=, &=, ^=, |= 11 1.6.12 Арифметические преобразования Если один из операндов имеет тип long double, double или float, то другие операнды преобразуются к одному и тому же типу, причем long double имеет максимальный приоритет. Иначе, если значения типа char, unsigned char, short int, unsigned short int могут быть представлены типом int, то все операнды указанных типов преобразуются в int, иначе в unsigned int. Затем, если один из операндов имеет тип unsigned long, то остальные преобразуются в unsigned long. Иначе, если один операнд имеет тип long int, а остальные — unsigned int, и long int может представлять все значения unsigned int, то unsigned int преобразуется в long int, иначе оба операнда преобразуются в тип unsigned long int. Иначе, если один из операндов long или int, то остальные преобразуются к тому же типу, причем long имеет максимальный приоритет. 1.7 Операторы 1.7.1 Оператор выражения Представляет собой выражение, заканчивающееся точкой с запятой. Language = “C#”; 1.7.2 Оператор метки Метка — это идентификатор, после имени которого ставится двоеточие. Оператор метки может быть использован в операторе goto (см. п. 2.7.5.4). 1.7.3 Пустой оператор Это просто точка с запятой. Используется, когда после метки или операторов while, do или for не должно следовать никакого оператора. while( !Завершено() ); 1.7.4 Составной оператор Представляет собой ноль или более операторов, заключенных в фигурные скобки. Допустим везде, где допустим оператор выражения. { int t = a; a = b; b = t; } 12 1.7.5 Управляющие конструкции Управляющие конструкции — средства, позволяющие создавать алгоритмы. Стандартными управляющими конструкциями являются if, for, while, goto. К тому же в C# есть несколько дополнительных конструкций: switch, do и foreach. 1.7.5.1 if..else Блок if..else, как следует из названия, позволяет выполнять код при выполнении определенного условия. if (a > b) { Console.WriteLine("a > b"); } else { Console.WriteLine("a <= b"); } Логическое выражение в скобках должно иметь тип bool (в отличие от C/C++, где выражение могло быть целым или указателем). Если оно истинно, выполнится первый блок команд, если ложно — второй. При этом если какой-либо блок команд состоит лишь из одной команды, обрамляющие фигурные скобки можно опустить: 1.7.5.2 if (serverObject != null) serverObject.Initialize(); for Цикл for представляет цикл с инициализирующей командой, условием окончания и командой перехода. ... double sum = 0; // сумма элементов // Складываем все элементы массива for (int i = 0; i<10; i++) { sum += array[i]; } Логика выполнения цикла следующая. Сначала выполняется инициализирующая команда (в примере — int i = 0), далее идет шаг цикла: проверяется условие окончания (i<10), если оно ложно, то цикл 13 прекращается и управление переходит на следующую за циклом команду, иначе выполняется тело цикла, а после него — команда перехода (i++). 1.7.5.3 while Цикл while является циклом с предусловием: сначала проверяется определенное условие перехода, а затем выполняется итерация цикла. int i=0; while (i<3) { i++; Console.WriteLine( i ); } На консоль будет выведено: 1 2 3 1.7.5.4 goto Оператор безусловного перехода goto применяется в двух ситуациях: когда нужно перейти на обработку определенного случая в блоке switch (он будет рассмотрен позднее, п. 2.7.5.5) или выполнить переход в определенное место программы. Во втором случае нужно указать метку в этом месте. Метка указывается следующим образом: в нужном месте программы указывается имя метки с двоеточием. Exit: // return 0; Чтобы перейти синтаксис: goto Exit; … на эту метку, используется следующий // Еще goto применяется, если нужно перейти к определенной ветви // в блоке switch: int level = GetLevel(); switch (level) { case 0: Console.WriteLine("Уровень 0"); break; case 1: goto case 2; 14 case 2: Console.WriteLine("Уровень 2"); goto default; default: Console.WriteLine("Выход"); break; } 1.7.5.5 switch Оператор switch является расширенным оператором ветвления, который позволяет в зависимости от значения выражения перейти к выполнению определенного кода. По сути, он эквивалентен набору блоков if, но более эффективен. … int a = 1; switch (a) { case 0: // Операторы, выполняющиеся если a = 0 Console.WriteLine("A = 0"); break; case 1: // Операторы, выполняющиеся если a = 1 Console.WriteLine("A = 1"); break; default: // Операторы, выполняющиеся, если ни случаев не подошел Console.WriteLine("A <> 0 и A <> 1"); break; } один из явных Блок case x выполняется, если выражение, указанное в скобках после switch равно x. Блок default — если ни одно из case-выражений не выполнилось. Удобно switch использовать для обработки выражений перечислимых типов. Для переходов между блоками можно использовать команды goto case и goto default. Для подробной информации смотрите описание оператора goto. В блоке case должно стоять константное выражение. 1.7.5.6 do 15 Оператор do реализует цикл с постусловием. Суть этого цикла аналогична while, но условие выхода проверяется не до итерации, а после. int i=0; do { i++; Console.WriteLine( i ); } while (i<3); На консоль будет выведено: 1 2 3 Обычно такой цикл применяют, когда проверку нужно выполнить после того, как прошла хотя бы одна итерация. 1.7.5.7 foreach foreach — оператор, облегчающий работу с коллекциями и массивами в C# . Он позволяет перебрать все элементы некоторой коллекции или массива. Синтаксис оператора foreach: foreach (тип идентификатор in коллекция_или_массив) оператор Тип идентификатора должен соответствовать типу коллекции или массива. Тип коллекции или массива должен реализовывать интерфейс IEnumerable или содержать метод GetEnumerator(). По своему действию оператор foreach аналогичен следующей конструкции. for (int i=0; i<коллекция_или_массив.Length; i++) { тип идентификатор = коллекция_или_массив[i]; оператор } Пример использования: вывод на консоль значений строкового массива. string[] диапазоны=new string[]{“НЧ”, “ВЧ”, “СВЧ”, “УВЧ”} foreach (string диапазон in диапазоны) { диапазон=”* “+диапазон+” *” 16 Console.WriteLine(диапазон); } На консоль будет выведено: * * * * НЧ * ВЧ * СВЧ * УВЧ * . 1.7.5.8 return Если функция не объявлена как void, она должна возвращать значение. И наоборот — функция не может возвращать значение, если она объявлена как void. Возвращаемое значение задается инструкцией return, например: int f1() { return 0; } char f2() { return ‘X’; } void f3() { return; } Операция return прерывает выполнение функции и устанавливает возвращаемое ей значение, для функций типа void значение не указывается. Функция может содержать более одной инструкции return. static int F(int a, int b) { return a + b; } static void Main() { int a= F(1, 2); Console.WriteLine(a.ToString()); } 1.7.5.9 if(a==3) return; else … break Прерывает выполнение последнего открытого оператора while, do, for, foreach или switch. Выполнение передается на оператор, следующий за прерванным. static void Main(string[] args) { 17 int i = 0; while (true) { if(i == args.Length) break; Console.WriteLine(args[i++]); } } 1.7.5.10 continue Передает управление на начало последнего открытого оператора while, do, for или foreach. static void Main(string[] args) { int i = 0; while (true) { Console.WriteLine(args[i++]); if(i < args.Length) continue; break; } } 18 2. Способы структурирования программы 2.1 Логическая организация программы Логическая организация кода помогает лучше в нем ориентироваться, делает код более понятным и облегчает его повторное использование. Язык C# использует принцип построения иерархической структуры пространств имен, принятый в .NET. Все классы проекта могут быть распределены в соответствии с его логической структурой по пространствам имен для образования единой иерархии. Правильное использование пространств имен делает классы более удобными в использовании и предотвращает конфликты с классами, написанными другими разработчиками. Например, стандартное пространство имен System включает в себя пространства имен Diagnostics, Collections и другие; а Collections включает в себя классы ArrayList, Comparer, Queue. Полные имена последних — System.Collections.ArrayList, System.Collections.Comparer и System.Collections.Queue. Для удобства программистов в C# используется директива using, позволяющая указывать короткие (не полные) имена классов и типов. Она указывает, какие пространства имен используются в программе. using System.Collections; class Application { public static void Main() { // Используем класс из пространства System.Collections. ArrayList list = new ArrayList (); … } } имен Часто бывает удобным именование членов иерархии (пространств имен) особенным образом: например, используя название компании-разработчика. Например, в компании HT Electronics, выполняющей работу над проектами Web Admin и Processor Manager, классы, относящиеся к этим проектам, могут быть расположены в пространствах имен HTElectronics.WebAdmin и HTElectronics.ProcessorManager. Также может быть определена общая библиотека классов в пространстве имен HTElectronics.Common. 2.2 Физическая организация программы Под физической организацией кода понимается его размещение по файлам и каталогам. Например, в Java существуют достаточно жесткие ограничения — 19 соответствие имен файлов именам классов, имен каталогов именам пакетов, размещение не более одного public-класса в файле и т.д. В C# подобных ограничений нет. Так что организация структуры файлов и каталогов возложена на программиста. В общем случае невозможно отразить структуру пространств имен структурой каталогов: в одном файле могут быть объявлены классы из разных пространств имен, и наоборот — одно пространство имен может быть представлено в нескольких файлах. Причем отсутствие ограничений не уменьшает логичности структуры, зато часто это удобно. 2.3 Объявления Описывают новый тип, переменную и ее тип, константу и ее значение или функцию, ее аргументы и возвращаемое значение. 2.3.1 Управление памятью Единственный способ создания нового объекта в С# — использовать ключевое слово new. // Объекты HelloClass будут созданы при вызове метода Main() using System; class HelloClass { public static void Main(string [] args) { // Новый объект можно создать в одной строке HelloClass c1=new HelloClass(); //…или в двух HelloClass c2; c2 = new HelloClass(); } } Ключевое слово new означает, что среде выполнения следует выделить необходимое количество оперативной памяти под экземпляр создаваемого объекта. Выделение памяти производится из “кучи”, находящейся в распоряжении среды выполнения .NET (managed heap — управляемой кучи). В нашем примере объекты создаются при помощи конструктора по умолчанию. Компилятор автоматически снабжает конструктором по умолчанию любой класс. Если есть необходимость, вы можете переопределить этот конструктор, заставив его выполнять нужные вам действия. Как и в С++, конструктор класса по умолчанию — это конструктор, который не принимает никаких параметров. Однако, если в С++ при создании объекта при помощи конструктора по умолчанию переменные остаются неинициализированными, 20 то в С# конструктор по умолчанию (как и все другие конструкторы), если не указано иное, присваивают всем данным состояния (например, переменным– членам) значение по умолчанию — в большинстве случаев это 0. Необходимо обратить внимание на то, что в программной логике метода Main() не предусмотрено никаких средств для удаления объектов с1 и с2. В С#, как и в Visual Basic, и в Java, программистам не надо думать о явном удалении объектов и освобождении памяти — сборщик мусора .NET (garbage collector, GC) освободит память автоматически. Среда выполнения удаляет объект из памяти, когда в текущей области видимости больше не остается активных ссылок на этот объект. … // Создаем локальный объект класса Газгольдер public static int Main(string []) args) { // Помещаем объект класса Газгольдер в управляемую кучу Газгольдер баллон_с_водородом=new Газгольдер (“Водород”, 200, 100) … return 0; } // Если баллон_с_водородом – единственная ссылка на этот объект, // то с этого момента он может быть удален 2.3.2 Типы данных Все типы в С# разделяются на две основные разновидности: структурные типы (value-based) и ссылочные типы (reference-based). Их отличие заключается в том, что переменные структурного типа содержат сами по себе все данные, в то время как переменные ссылочных типов лишь ссылаются на некоторое значение. 2.3.2.1 Структурные типы Структурные типы делятся на несколько групп. Это могут быть структуры, перечисления, числовые типы (которые, в свою очередь делятся на целые, вещественные и тип decimal) и булевый тип. 2.3.2.1.1 Простые типы Целые типы Название Диапазон значений типа sbyte –128..127 Размер Знаковое 8-битное целое 21 byte 0..255 char U+0000..U+FFFF short –32.768..32.767 ushort 0.65535 int –2.147.483.648..2.147.483.647 uint 0..4.294.967.295 long –9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807 0..18,446,744,073,709,551,615 ulong Беззнаковое 8-битное целое 16-битный Unicodeсимвол Знаковое 16-битное целое Беззнаковое 16-битное целое Знаковое 32-битное целое Беззнаковое 32-битное целое Знаковое 64-битное целое Беззнаковое 64-битное целое Из особенностей отметим наличие 64-битных чисел и представление всех символов как Unicode (соответственно отсутствуют знаковые/беззнаковые символьные типы). Типы с плавающей точкой (вещественные) Название типа float double Примерный диапазон значений +1.5E–45..+3.4E38 +5.0E–324..+1.7E308 Точность 7 знаков 15–16 знаков Тип decimal Тип decimal описывает 128-битный числовой тип. Он может быть как целым, так и вещественным с большой точностью, что делает его популярным для хранения денежных сумм. Название типа Decimal 2.3.2.1.2 Примерный Диапазон значений 1.0E–28 to 7.9E28 Точность 28–39 значащих цифр Векторы (массивы) Это непрерывные блоки памяти, хранящие множество элементов, одного и того же типа. Объявляются посредством указания числа элементов, которое должно быть положительным целым константным выражением, заключенным в квадратные скобки []. Массивы могут быть как одномерными, так и многомерными. // Одномерный вектор из 10 вещественных чисел 22 float [] a = new float[10]; // Матрица из 6464 целочисленных значений int [,] b = new int[64, 64]; // Вектор из 16 символьных векторов char [][] c = new char [16][]; Векторы могут быть инициализированы при объявлении, например: int [] четные_числа = new int [] {0, 2, 4, 6, 8}; Также допустима короткая форма записи (только при объявлении массива): int [] четные_числа = {0, 2, 4, 6, 8}; int [] нечетные_числа; нечетные_числа = {1, 3, 5, 7, 9}; // Ошибка! При объявлении вложенных инициализироваться отдельно. векторов каждый элемент должен double [][] массив = new double [2][]; массив[0] = new double [3]; массив[1] = new double [4]; Возможна инициализация при объявлении: double [][] массив = new double [2][] { new double [3], new double [4] } Работа с многомерными массивами аналогична работе с одномерными. 2.3.2.1.3 // Создание массива int [,] двумерный_массив = new int [8, 8]; // Доступ к элементам двумерный_массив[0, 4] = 600; // Присваивание (новый экземпляр) двумерный_массив = new int [,] { {0, 1}, {1, 0} }; Перечисления Переменные типа перечисления могут принимать одно из заданных (перечисленных) значений. Значения задаются при определении типа. Также бывают битовые перечисления, в которых значения могут комбинироваться. Например, определим перечисление, описывающее время года: public enum Времена_года {Зима, Весна, Лето, Осень}; 23 По умолчанию значения перечислений соответствуют целым числам, начиная с нуля (т.е. в приведенном примере значение Времена_года.Зима равно нулю, Времена_года.Весна — единице и т.д.), но допустимо определение перечислений с явным указанием значений: public enum Статус { OK = 200, Запрещено = 403, Не_найдено = 404 }; 2.3.2.1.4 Константы Константы – это объекты, значение которых после инициализации не может быть изменено (это должно быть сделано во время инициализации). const double pi = 3.14159265358979323846; const string warning = “Внимание!”; 2.3.2.1.5 Структуры Структуры являются аналогом классов, но в отличие от них являются структурным (не ссылочным) типом. То есть структуры передаются по значению, а не по ссылке. Синтаксис для объявления структуры очень похож на объявление класса: public struct Point { public int x, y; public Point(int p1, int p2) { x = p1; y = p2; } } Эта структура описывает точку на плоскости. Для структур в С# не существует единого базового класса (тип System.Structure в С# не определен), однако косвенно все структуры являются производными от типа ValueType. Основное назначение ValueType заключается в том, чтобы обеспечить типы данных, производные от System.Object, членами для работы с этими типами данных как со структурными (value-based), когда значения передаются как локальные копии, а не как ссылки на области в памяти. 24 2.3.2.2 Ссылочные типы При создании нового объекта ссылочного типа сам объект создается в специальном пуле, а переменная представляет всего лишь ссылку на него: class MyClass { ... } … MyClass a = new MyClass(); Если мы далее присваиваем другой переменной значение только что созданной, для нее не создается нового объекта, она просто ссылается на существующий: MyClass b = a; При этом все изменения объекта, которые производятся через b отражаются и на a. Также значения ссылок a и b можно изменять — при этом они перестают ссылаться на текущий объект и ссылаются на новый (или не ссылаются ни на что — имеют значение null). Если возникает ситуация, что все ссылки на объект изменили свои значения и на объект больше никто не ссылается, то он становится «бесхозным» — и удаляется. a = null; b = null; Прочие отличия структурных и ссылочных типов сведены в таблицу 3.1. Таб.3.1 Отличия структурных и ссылочных типов «Интегрирующий Структурные типы вопрос» Где размещаются эти В области стека типы? Как будет В виде локальной копии представлена типа переменная, которой в качестве значения присвоен этот тип? Что может являться Эти типы могут для них базовым производится только на типом? прямую от типа System.ValueType Ссылочные типы В области управляемой кучи В виде указателя на область оперативной памяти, относящейся к объекту этого типа Могут производится от любого другого типа (за исключением System.ValueType), если этот тип не является закрытым. Может ли этот тип Нет. Структурные типы Да, если этот ссылочный 25 выступать в качестве всегда закрыты и базового? дополнение их другими свойствами не предусмотрено. Поэтому они не могут выступать при наследовании в качестве базового для других типов. Как производится Как значений (то есть передача параметров? вызывающей функции передаются только локальные копии значений переменных) Существует ли Нет. Структурные типы возможность никогда не размещаются переопределить в куче и поэтому к ним Object.Finalize()? не применяется функция завершения. Можно ли определить Да, но конструктор по конструкторы для умолчанию этого типа? зарезервирован (то есть все пользовательские конструкторы должны принимать параметры) Когда происходит Когда происходит выход «смерть» переменной за область видимости данного типа? тип не определен внутренне как закрытый. Как ссылок (то есть вызывающей функции передается ссылка на адрес данного объекта в оперативной памяти) Да, но не напрямую. Да. Во время процесса сборки мусора (garbage collection) в управляемой куче Несмотря на все различия, и структурные, и ссылочные типы могут реализовывать стандартные (то есть встроенные) и пользовательские интерфейсы и могут поддерживать любое количество полей, методов, свойств и событий. 26 2.4 Классы Одним из основных понятий объектно-ориентированного программирования является класс. Соответственно, это понятие занимает центральное место и в идеологии C#. 2.4.1 Объявление Объявление класса вводит новый тип и устанавливает ограничение доступа к членам класса. Класс объявляется с помощью ключевого слова class. [модификаторы] class имя_класса [: базовый_класс] { тело класса; } Модификаторы доступа: new public protected internal private abstract sealed Например: public class HelloWorldClass { public void HelloWorld() { Console.WriteLine("Здравствуй, мир!"); } } Класс, объявленный как public, доступен отовсюду, включая другие сборки. Если класс объявлен как internal, он будет доступен только из текущей сборки. Существует возможность сделать класс абстрактным: public abstract class Баллон { public int Объем() { // Код, расположенный здесь наследуется потомками. … } 27 // Данный метод необходимо определять для каждого потомка public abstract void Открыть(); } Такие классы могут содержать абстрактные методы (методы, которые не реализованы в текущем классе, но должны быть реализованы в неабстрактных потомках). Запрещено создавать экземпляры абстрактных классов (генерируется ошибка времени компиляции). То есть для использования абстрактного класса, должен быть определен потомок. public class Кислородный_баллон: Баллон { public override void Открыть() { //Здесь содержится код, выполняемый только для // экземпляров класса Кислородный_баллон … } } Если же необходимо, чтобы у класса не было потомков, его нужно объявить как sealed (запечатанный). public sealed class Пульт_управления { … } … // Это приведет к ошибке компиляции public class Выносная_консоль: Пульт_управления { … } После двоеточия указывается класс, от которого наследуется данный. В C# запрещено множественное наследование: класс-потомок может иметь только один базовый класс, но он может реализовывать несколько интерфейсов. public class Датчик_давления { … } public class Датчик_температуры { … } 28 public interface Калибратор { … } public interface Протокол { … } // Попытка наследования от нескольких классов приведет к ошибке // компиляции public class Универсальный_сенсор : Датчик_давления, Датчик_температуры, { … } // Зато можно реализовывать несколько интерфейсов public class Прецизионный_датчик_давления: Датчик_давления, Калибратор, Протокол { … } Если базовый класс не указан, то класс автоматически является наследником класса System.Object (или просто object). 2.4.2 Члены класса В теле класса объявляются его члены: поля, методы и свойства. 2.4.2.1 Поля Поле представляет переменную, связанную с данным классом или его экземпляром. Модификаторы доступа: new public protected internal private static readonly volatile 29 По умолчанию: если не указан ни один модификатор доступа — поля (так же, как методы и свойства) являются закрытыми (private). public class MyClass { // Поле доступно из любого класса. public int size; // Поле доступно только классов-наследников protected double coeff; из текущего класса и // Поле доступно только внутри класса. private string name; // Задаем начальные значения в конструкторе public MyClass() { size = 5; coeff = 1.0; name = “Сигнал”; } } public class Application { public static void Main() { MyClass myClass = new MyClass(); // size = 5; Console.WriteLine("size = {0}", myClass.size); myClass.size += 5; // size = 10 Console.WriteLine("size = {0}", myClass.size); } } Также можно объявить поле как readonly — запрещается запись в поле, кроме как посредством инициализатора или в теле конструктора. public class MyClass { // Задаем начальное значение при инициализации public readonly int size = 10; // Задаем значение в конструкторе public MyClass() { 30 size = 16; } public SetSize() { size = 8; // Ошибка компиляции } } Модификатор volatile запрещает некоторые оптимизации, которые могут привести к непредсказуемым последствиям в многопоточных приложениях. Модификатор static декларирует принадлежность члена всему классу, а не конкретному экземпляру. Доступ к таким членам осуществляется через имя класса, а не его экземпляра. public class A { // Количество экземпляров данного класса public static int количество_экземпляров = 0; public A() { количество_экземпляров++; // Увеличиваем счетчик экземпляров на 1 } ~A() { количество_экземпляров--; // Уменьшаем счетчик экземпляров на 1 } } public class Б { public static void Main() { A a1=new A(); A a2=new A(); A a3=new A(); Console.WriteLine(“Количество экземпляров: {0}“, A.количество_экземпляров); } } На консоль будет выведено: 31 Количество экземпляров: 3 2.4.2.2 Методы Методы представляют собой функции-члены: действия, которые можно произвести с экземпляром класса или с классом (статические методы). Модификаторы доступа: new public protected internal private static virtual sealed override abstract extern public class Пример_класса { private int _a; private int _b; public Пример_класса(int a, int b) { _a = a; _b = b; } public int Max() { // Возвращаем наибольшее значение из (a, b) return _a > _b ? _a : _b; } } public class Application { public static void Main() { Пример_класса максимум = new Пример_класса (2, 10); // MAX(2, 10) = 10 Console.WriteLine("MAX(2, 10) = {0}", максимум.Max()); } } 32 Модификатор static означает то же, что и в случае полей. Он указывает, что метод принадлежит всему классу, а не конкретному экземпляру; работать такой метод может только со статическими членами: public class Пример_static { public static int _a; public int _b; public void Установить_b() { _b = _a; } } public class Application { public static void Main() { Пример_static экз1 = new Пример_static(), экз2 = new Пример_static(); Пример_static._a = 1; экз1.Установить_b(); Пример_static._a = 2; экз2.Установить_b(); Console.WriteLine("экз1._b = {0}, экз2._b = {1}", экз1._b, экз2._b); } } Модификатор virtual указывает, что метод может быть переопределен (override) в потомках. Для перегрузки методов в потомках используются модификаторы new и override. При использовании модификатора new, метод потомка скрывает одноименный метод родительского класса, а при использовании override метод потомка скрывает одноименный виртуальный (virtual) метод родительского класса. class Базовый_класс { public void Метод_А() { Console.WriteLine("Базовый_класс.Метод_А"); } 33 public virtual void Метод_Б() { Console.WriteLine("Базовый_класс.Метод_Б"); } } class Класс_потомок : Базовый_класс { public new void Метод_А() { Console.WriteLine("Класс_потомок.Метод_А"); } public override void Метод_Б() { Console.WriteLine("Класс_потомок.Метод_Б"); } } class Application { static void Main(string[] args) { // Создаем экземпляр Класс_потомок() и храним его в объекте // типа Базовый_класс. Базовый_класс потомок = (Базовый_класс)new Класс_потомок(); // Будет вызван метод базового класса, т.к. объект потомок – типа // Базовый_класс потомок.Метод_А(); // Будет вызван метод класса-потомка, переопределенный в классе // Класс_потомок потомок.Метод_Б(); } } Методы могут иметь параметры. Формат списка параметров следующий. [модификатор параметра] тип_параметра имя_параметра Существуют следующие модификаторы параметров: out ref 34 Модификатор out указывает, что значение параметра не передается в метод, а возвращается из него. Реально это означает, что можно передавать только переменную, она может быть не инициализирована и ее значение может быть изменено в методе. Модификатор ref указывает, что параметр передается по ссылке. То есть, если в теле метода будет изменено его значение, изменится и значение передаваемой переменной. С модификатором ref могут передаваться только переменные. Если не указан ни один из модификаторов, параметр (переменная или константа) передается в метод; все операции над переменной сохраняются только внутри метода. Также существует возможность декларировать метод как принимающий произвольное число аргументов. Для этого используется следующий синтаксис: params [тип элемента][] <имя списка> Например: class Application { static void Метод_с_params(string text, params string[] args) { Console.WriteLine(text); foreach(string s in args) Console.WriteLine(s); } public static void Main() { Метод_с_params("Времена года: ", "Весна", "Лето", "Осень", "Зима"); } } 2.4.2.3 Cвойства Свойства расширяют возможности полей. Они представляют собой типизированные объекты, у которых можно получить значение или записать в 35 них новое значение. При выполнении определяемый программистом код. этих действий выполняется Модификаторы доступа к свойствам: new public protected internal private static virtual sealed override abstract extern Синтаксис для определения свойств следующий. [модификаторы] тип имя { get { код, выполняющийся при получении значения свойства return величина того же типа, что и свойство; } set { код, выполняющийся при установке значения свойства переменная того же типа, что и свойство = value; } } Тело get содержит код, который выполняется при получении значения свойства. Тело set — код, который выполняется при установке нового значения. При этом в set доступно присваиваемое значение через ключевое слово value. public class Пример_свойств { private static int _значение; private static int _число_обращений = 0; // Свойство – целое число с подсчетом количества изменений значения. public static int Значение { get { return _значение; } set 36 { _число_обращений++; _значение = value; } } public static void Main() { Значение = 2; Console.WriteLine("Значение = {0}", Значение); } } При определении свойств класса часто возникает необходимость создать свойство, которое будет доступно только для чтения. Делается это очень просто: необходимо в определении свойства пропустить блок set. В результате свойство станет доступным только для чтения. public class Вольтметр { private double _напряжение; … // Свойство доступно только для чтения public double Напряжение { get { // Выполняется некоторый код. … return _напряжение; } } } Кроме того, можно создать свойства, доступные только для записи: у них отсутствует блок get, и имеется только блок set. C# также поддерживает статические свойства. Обращение к статическим свойствам производится так же, как и к статическим методам и полям. 2.4.2.4 Индексаторы При написании приложений часто возникает необходимость создавать объекты, представляющие коллекцию других объектов (они не обязательно явно хранят в себе все эти объекты, но предоставляют доступ к ним). В некоторых языках (например, Java) для этого использовались специальные функции вроде GetItem(int index). Для упрощения синтаксиса доступа к объектам коллекции в C# используются индексаторы (indexers). Они 37 предоставляют синтаксис, сходный с используемым при адресации массива, за исключением того, что в качестве индекса может использоваться любой тип данных. Модификаторы доступа: new public protected internal private virtual sealed override abstract extern Для того, чтобы объявить в классе индексатор, нужно использовать следующий синтаксис: [тип] this [список_параметров] Здесь тип — это тип возвращаемого значения (т.е. тип элемента коллекции), а список параметров — типы и имена параметров, используемых для идентификации элемента коллекции. Индексатор может иметь любые модификаторы, кроме static, а к параметрам нельзя применять модификаторы out и ref. Для определения кода индексатора нужно задать методы доступа — get и/или set (если индексатор позволяет менять элементы). При этом в блоке get доступны все параметры индексатора как переменные, а в методе set — дополнительно к ним параметр value, представляющий новое значение элемента. Таким образом, индексатор примет вид, аналогичный следующему. … private object GetItem(int index){…} private void SetItem(int index, object val){…} public object this [int index] { get { return GetItem(index); } set { SetItem(index, value); } } 38 2.4.2.5 Конструкторы Конструкторы экземпляров предназначены для инициализации вновь созданных экземпляров класса. Это специальный тип метода, который присваивает начальные значение членам класса, производит другие инициализирующие действия. Важным моментом здесь является инициализация базового класса. Для вызова конструктора базового класса используется ключевое слово base. class Базовый_класс { int _a; public Базовый_класс(int a) { _a = a; } } class Класс_потомок: Базовый_класс { // Поле _a базового класса инициализируется единицей. public Класс_потомок (): base(1) { } } Статические конструкторы инициализируют класс в целом. Момент его вызова неизвестен — гарантируется лишь то, что он будет вызван до создания первого экземпляра класса. Единственное назначение статических конструкторов — присваивать исходные значения статическим переменным. public class АЦП { … private static string _разработчик; public static string Разработчик { get { return _разработчик; } } static АЦП() 39 { _разработчик = ”Argusslent, Inc”; } … } public static void Main() { Console.WriteLine(“Производитель АЦП.Разработчик); } 2.4.2.6 устройства: {0}”, Деструкторы Деструктор — это метод, который вызывается при уничтожении объекта. Так как в .NET CLR используется сборщик мусора, нельзя явно удалить определенный экземпляр. Удаление объекта происходит при первой сборке мусора — после того, когда на экземпляр уже нет активных ссылок. Деструкторы определяются как методы с именем, совпадающим с именем класса, предваренным знаком ~ (тильда). Деструктор не может иметь параметров и модификаторов; он не может быть вызван явно, т.к. его вызов осуществляется автоматически при сборке мусора. Несмотря на схожесть синтаксиса деструкторов в C# и деструкторов в неуправляемом C++, они имеют совершенно различный смысл. Например, изза недетерминированности момента разрушения объектов в теле деструктора нельзя обращаться к полям объекта (это может привести к сбою во время исполнения): объекты-поля могут быть разрушены до объекта-оболочки, что невозможно в неуправляемом C++. public class A { ~A() { Console.WriteLine("Объект класса А разрушен!"); } } public class Application { public static void Main() { A a = new A(); // Присваиваем переменной a значение null, тем самым удаляя // единственную активную ссылку на объект. a = null; // Вручную требуем произвести сбор мусора. GC.Collect(); 40 Console.WriteLine("Приложение завершено!"); } } Программа выведет «Объект класса А разрушен!», а затем — «Приложение завершено!». Это означает, что сборщик мусора определил объект, созданный оператором new как неиспользуемый, и вызвал для него деструктор. Инкапсуляция 2.4.3 Под инкапсуляцией понимается комбинирование данных и функций, манипулирующих этими данными, в единый объект (класс), а также способность классов скрывать детали реализации от пользователей. Т. е. класс может иметь большое количество закрытых членов и методов, открытые методы могут быть реализованы сложным образом, но пользователь класса будет видеть только небольшое количество открытых методов, а их реализация будет скрыта от него. 2.4.4 Наследование Наследование — возможность создавать новые определения классов на основе существующих. Наследование помогает пользователям расширять возможности базового класса в производном. При наследовании производный класс получает от базового класса все открытые (public) и защищенные (protected) члены, то есть объект производного класса является в полной мере объектом базового класса. В C# для указания базового класса используется двоеточие. class A { public int a; public void Увеличить() { a++; } } // Класс B – потомок класса A. Он наследует поле a и метод Увеличить() базового // класса. class B: A { public void Уменьшить() { 41 a--; } } class Application { public static void Main() { B b = new B(); A a = (A)b; a.a = 0; // A = 0 Console.WriteLine("A = {0}", b.a); a.Увеличить(); // A = 1 Console.WriteLine("A = {0}", b.a); // Ошибка // a.Уменьшить(); b.Уменьшить(); // A = 0 Console.WriteLine("A = {0}", b.a); } } Для вызова конструктора базового класса при конструировании экземпляра производного класса используется ключевое слово base. public Формирователь_прямоугольных_импульсов( double амплитуда, double период, double скважность): base(амплитуда, период) { _скважность = скважность; } В С# множественное наследование запрещено: при создании производного класса в качестве базового класса можно указать только один класс. Классическое наследование — это очень удобный способ определить набор характеристик для класса. Однако иногда встречаются ситуации, когда необходимо запретить производить наследование от какого-либо класса. В С# для запрещения наследования предусмотрено ключевое слово sealed. 42 // Запрещаем классу Формирователь_прямоугольных_импульсов выступать // в качестве базового для остальных классов. public sealed class Формирователь_прямоугольных_импульсов: Формирователь_сигнала { public Формирователь_прямоугольных_импульсов( double амплитуда, double период, double скважность): base(амплитуда, период) { // Код конструктора } // Члены класса … } Поскольку класс Формирователь_прямоугольных_импульсов объявлен как закрытый для наследования, его нельзя использовать в качестве базового для остальных классов. Подобный код приведет к ошибке компилятора: // Ошибка, sealed-класс не может выступать в базового. public class Формирователь_квадратных_импульсов: качестве Формирователь_прямоугольных_импульсов { … } Полиморфизм 2.4.5 Полиморфизм позволяет переопределить реакцию объекта производного класса на метод, определенный в базовом классе. Для реализации полиморфизма используются ключевые слова С#: virtual и override. Если базовый класс определяет метод, который должен быть замещен в производном классе, этот метод должен быть объявлен как виртуальный: public class Формирователь_сигнала { public virtual double Мощность() { double мощность; … return мощность; } … } 43 Если необходимо переопределить виртуальный метод, необходимо заново определить этот метод в производном классе, используя ключевое слово override. public class Формирователь_синусоидальных_импульсов: Формирователь_сигнала { public override double Мощность() { double коэфф; … return коэфф * base.Мощность(); } … } В приведенном примере замещенный метод использует вызов этого же метода базового класса. Таким образом, нет необходимости заново определять всю логику замещенного метода в производном классе: вполне достаточно воспользоваться вариантом метода по умолчанию, определенном в базовом классе, дополнив его нужными действиями. 2.5 Структуры Структуры похожи на классы тем, что они также являются набором данных и функций для работы с этими данными. Однако, в отличие от классов, структуры относятся к типам-значениям и не требуют размещения в куче (heap). Переменная структурного типа содержит в себе данные структуры, тогда как объект класса содержит ссылку на данные класса. Структуры оказываются полезными для представления небольшого объема данных с семантикой значений. Это, например, комплексные числа, координаты точки на плоскости или в пространстве, пары значений в словаре и т.д. 2.5.1 Объявление Структура объявляется с помощью ключевого слова struct. struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } 44 Модификаторы доступа: new public protected internal private Модификаторы доступа структуры имеют то же смысл, что и в случае классов (п.3.2.2). 2.5.2 Члены структуры Структуры могу содержать любое количество внутренних членов. Членами структур могут являться: константы поля методы свойства индексаторы конструкторы 2.5.3 Различия структур и классов Структуры относятся к размерным типам, классы — к ссылочным. Размерные типы являются производными от System.ValueType. Этот тип имеет те же методы, что и System.Object. Поскольку в объявлении нового размерного или ссылочного типа нельзя указывать размерный тип в качестве базового класса, то вводить в размерный тип новые виртуальные методы нельзя. Методы не могут быть абстрактными и неявно являются изолированными (т.е. не могут быть переопределены). Экземпляры ссылочных типов размещаются в свободной памяти (в куче, heap), а типы-значения размещаются в стеке создающего их потока. Это существенно различающиеся по своим свойствам способы выделения памяти. Переменные ссылочных типов содержат адреса объектов, а переменные типов-значений содержат сами объекты (их тела). Поэтому обращение к полям value-типов осуществляется непосредственно, без лишней косвенности. 45 Для ссылочных типов, и для типов-значений применяется единый синтаксис инициализации объекта. Но, несмотря на использование оператора new, value-типы создаются в стеке. AClass c = new AClass(); AValue a = new AValue(); // размещается в куче // размещается в стеке Отличие состоит в том, что value-типы могут создаваться и без применения оператора new. В этом случае объект value-типа создаётся неинициализированным (под него только выделяется память), и вам придётся его инициализировать перед первым использованием. Причем компилятор будет следить за этим, и не позволит использовать объект до тех пор, пока все поля не будут проинициализированы. AValue a; a.n = 5; // a.s = "6"; Console.WriteLine(a); // error CS0165: Use of unassigned local variable 'a' На конструктор value-типа накладывается ограничение — он должен обязательно проинициализировать все поля объекта. За этим опять будет следить компилятор. struct AValue { AValue(int n){ this.n = n; } 'Values.AValue.s' must be // error CS0171: Field // fully assigned before control leaves // the constructor AValue(){ this.n = 5; this.s = "6"; } CS0568: Structs cannot contain // explicit parameterless constructors public int n; public string s; // остался не проинициализированным } // error Ещё одно ограничение — конструктор обязательно должен иметь параметры. Для типов-значений нельзя задать свой конструктор по умолчанию (без параметров). По законам .Net используемый по умолчанию конструктор value-типа должен всегда инициализировать все поля нулями (0 или null). У типов-значений не бывает деструкторов. 46 Объекты ссылочных типов передаются как параметры методов по ссылке, а объекты типов-значений по значению. Это означает, что в случае ссылочного типа копируется сама ссылка (указатель), а при передаче типазначения копируются все его поля. Если структура состоит из одного-двух полей небольшого размера, передача ее в качестве параметра происходит даже быстрее, чем передача ссылки на объект, так как отсутствуют дополнительные операторы взятия и разрешения ссылки. Но при больших размерах структуры эффективность ее передачи в качестве параметра резко снижается. Увеличить производительность передачи структуры можно, объявив параметр как ссылку с ключевым словом ref. Но при этом исходное содержимое структуры может быть изменено внутри вызываемого метода. 2.6 Массивы Массив — это набор однотипных значений, рассматриваемый как единое целое. 2.6.1 Типы массива Общеязыковая исполняющая среда Microsoft .Net (CLR) поддерживает массивы: одномерные (single-dimensional); многомерные (multidimensional); вложенные (jagged). Базовым для всех массивов является тип System.Array, производный от System.Object. Массивы всегда относятся к ссылочному типу и размещаются в управляемой куче, а переменные содержат не сам массив, а ссылку на него. 2.6.2 Объявление массива // Одномерные массивы: int [] array = new int[10]; int [] array = new int[]{1, 2, 3, 4, 5}; Доступ к элементам производится с помощью оператора [], элементы нумеруются индексами от 0 до (N – 1), где N — размер массива. int element = array[0]; // Многомерные массивы: int [,] array = new int[10, 20]; int [,] array = {{1, 2}, {3, 4}}; 47 Доступ к элементам производится с помощью оператора [], в котором индексы также указываются через запятую. Элементы нумеруются наборами индексов, каждый из которых может принимать значение от 0 до (N – 1), где N — размер соответствующего измерения массива. int element = array[0, 2]; Вложенные массивы: int [][] array = new int[2][]; array[0] = new int[4]; array[1] = new int[20]; Доступ: int element = array[0][1]; 2.6.3 Члены массива У типа System.Array есть несколько статических и экземплярных членов. Поскольку все массивы являются неявно производными от System.Array, эти члены можно использовать для работы с массивами и размерных и ссылочных типов. 2.7 Интерфейсы Интерфейсы предоставляют средство обобщения классов, от которых требуются однотипная реакция на определенные вызовы. Список вызовов, на которые должен реагировать класс (эти вызовы могут быть представлены в форме вызовов методов, изменении значений свойств и индексаторов, генерации событий) собираются в интерфейсе. Интерфейсы никогда не являются типами данных, и в них не бывает реализации методов по умолчанию. Каждый член интерфейса (свойство или метод) автоматически становится абстрактным. Интерфейсы могут содержать в себе свойства, методы, индексаторы и события, но не могут содержать их реализации. Они лишь декларируют, какие члены должны содержать классы и структуры, реализующие данный интерфейс. 2.7.1 Объявление С точки зрения синтаксиса интерфейсы в С# определяются следующим образом. [модификаторы] interface имя_интерфейса: [базовые интерфейсы] { [Свойства интерфейса] 48 [Методы интерфейса] [Индексаторы интерфейса] [События интерфейса] } Из модификаторов доступа разрешены new, public, protected, internal и private. // Этот интерфейс определяет работу с многогранниками public interface IPolyhedron { … int GetNumberOfEdges(); … } 2.7.2 Члены интерфейса Интерфейс может содержать любое количество членов. Членами интерфейса могут быть методы, свойства, события, или индексаторы. С# не допускает определения статических членов интерфейса. Кроме того, интерфейс не может иметь экземплярные поля и конструкторы. Например, рассмотрим интерфейс, который содержит каждый из возможных видов членов: метод, свойство, событие, и индексатор. public delegate void StringListEvent(IStringList sender); public interface IstringList { // Метод void Add(string s); // Свойство – только для чтения int Count { get; } // Событие event StringListEvent Changed; // Индексатор, предоставляющий доступ как для чтения, так и для записи string this[int index] { get; set; } } Интерфейс — это просто абстрактный тип, состоящий из набора виртуальных методов, каждый из которых имеет свое имя, параметры и возвращаемый тип. Методы интерфейса не могут иметь реализации, так что они являются незавершенными (абстрактными). Интерфейсы .NET могут поддерживать любое количество свойств. public interface IPolyhedron 49 { int NumberOfEdges { get; set; } } Чтобы определить свойство только для чтения или только для записи достаточно просто не указать соответствующий блок (set или get). 2.7.3 Реализация интерфейса Когда в C# какой-либо класс должен реализовать нужные пользователь интерфейсы, названия этих интерфейсов должны быть помещены (через запятую) после двоеточия, следующего за именем этого класса. interface ICloneable { object Clone(); } interface IComparable { int CompareTo(object other); } class ListEntry: ICloneable, IComparable { public object Clone() {...} public int CompareTo(object other) {...} } В классе обязательно должны быть реализованы все методы данного интерфейса. 2.7.4 Наследование В C# два интерфейса могут вступать между собой в отношения наследования, при которых один интерфейс станет базовым, а другой — производным. Базовый интерфейс определяет общее поведение, в то время как производный интерфейс — более конкретное и специфическое. // Базовый интерфейс interface IDraw { void Draw(); } interface IDraw2 : IDraw { void DrawToPrinter(); } interface IDraw3 : IDraw2 50 { void DrawToMetafile(); } Если реализуемый класс должен поддерживать поведение, определенное во всех трех интерфейсах, он должен производиться от интерфейса самого верхнего уровня (в нашем случае – IDraw3). Все методы, определенные в базовых интерфейсах, будут автоматически включены в производные интерфейсы. // Этот класс будет поддерживать IDraw, IDraw2, IDraw3 public class SuperImage : IDraw3 { // Используем явную реализацию интерфейсов, чтобы привязать методы // к конкретным интерфейсам void IDraw.IDraw() { // Обычный вывод на экран } void IDraw2.IDrawToPrinter() { // Вывод на принтер } void IDraw3. IDrawToMetafile() { // Вывод в метафайл } } В С# допускается наследование сразу от нескольких базовых интерфейсов (в отличие от классов). Предположим, что в распоряжении пользователя есть набор интерфейсов, моделирующих поведение автомобиля: interface IBasicCar { void Drive(); } interface IUnderWaterCar { void Dive(); } // А это интерфейс, производный сразу от двух предыдущих: interface IJamesBondCar : IBasicCar, IUnderWaterCar { void TurboBoost(); 51 } Если необходимо создать класс, который реализует интерфейс IJamesBondCar, нам придется реализовать в нем все методы каждого из интерфейсов. public class JBСar : IJamesBondCar { public JBCar() {} // Унаследованные члены void IBasicCar.Drive() { Console.WriteLine(“Ускорение…”) } void IUnderWaterCar () { Console.WriteLine(“Погружение…”)} void IJamesBondCar () { Console.WriteLine(“Отрыв!”) } } 2.8 Перегрузка операций В дополнение к стандартным интерпретациям унарных и бинарных операторов в C# есть возможность для классов и структур переопределить их значение. Для этого используется ключевое слово operator. Обратите внимание, что его можно использовать только вместе с ключевым словом static. Можно перегружать следующие операторы: унарные +, –, !, ~, ++, --, true, false и бинарные +, –, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=, <=, к тому же при перегрузке бинарных операторов перегружается и соответствующие оператор присваивания: например для + автоматически перегружается +=. 2.8.1 Унарные операции При перегрузке унарных операторов используется синтаксис operator символ оператора ( параметр ) 2.8.2 Бинарные операции При перегрузке бинарных операторов используется синтаксис operator символ оператора ( оператор 1, оператор 2 ) Например: public struct Vector { private double x, y; public Vector( double x, double y ) 52 { this.x = x; this.y = y; } // Перегружаем оператор сложения public static Vector operator + ( Vector a, Vector b ) { return new Vector(a.x + b.x, a.y + b.y); } public override string ToString() { return "[" + x + ", " + y + "]"; } } public class Application { public static void Main() { Vector a = new Vector(1, 2); Vector b = new Vector(2, 3); Vector c = a + b; Console.WriteLine("{0} + {1} = {2}", a, b, c); } } Необходимо отметить, что не все операторы можно перегрузить. Информация о перегружаемости операторов представлена в следующей таблице: Таб. 3.2Возможность перегрузки операторов в С# Оператор С# +, –, !, ~, ++, --, true, false +, –, *, /, %, &, |, ^, <<, >> ==, !=, <, >, <=,>= [] Можно ли произвести перегрузку Любой оператор из этого набора унарных операторов может быть перегружен Любой оператор из этого набора бинарных операторов может быть перегружен Все эти операторы сравнения могут быть перегружены Этот оператор не может быть перегружен. Однако можно применять его к конкретному классу, если в нем реализован метод индексатора 53 2.9 Делегаты В платформе .NET, и соответственно в C#, реализована концепция делегатов — объектно-ориентированного подобия указателей на функции в C++. При помощи делегатов поддерживается механизм функций обратного вызова. В отличие от механизмов обратного вызова из других платформ, таких как С++, функциональность делегатов намного богаче. Например, делегаты обеспечивают безопасность типов при исполнении метода обратного вызова. Делегаты также поддерживают последовательный вызов нескольких методов и позволяют вызывать как статические, так и экземплярные методы. 2.9.1 Объявление Объявление делегатов имеет следующий синтаксис. [модификаторы] delegate тип идентификатор ([параметры]); Допустимы следующие модификаторы: new public protected internal private Объявление делегата создает класс, а не просто указатель на метод, именно поэтому не нарушаются объектно-ориентированные концепции. Делегат может существовать отдельно от логически связанного с ним класса, а может быть помещен непосредственно внутрь определения класса, тогда он будет вложенным классом. Например: delegate int D(int i, double d); class A { public static int M(int a, double b) {...} } class B { delegate int D(int c, double d); public static int M(int f, double g) {...} } Существует два типа делегатов — одиночные (Singlecast) и комбинированные (Multicast). С точки зрения синтаксиса объявления они различаются только типом возвращаемого значения. При описании одиночных 54 делегатов создается класс, наследующий System.Delegate, а при описании комбинированных — наследующий System.MulticastDelegate. 2.9.2 Одиночные делегаты Пример использования одиночного делегата. using System; public delegate int SingleDelegate(int x); public class SampleDelegateClass { int sampleMethod(int x) { // … Console.WriteLine(x); return 0; } public static void Main(String[] args) { // Создаем экземпляр этого класса SampleDelegateClass sdc = new SampleDelegateClass(); //Создаем экземпляр делегата SingleDelegate sDelegate = new SingleDelegate(sdc.sampleMethod); Console.WriteLine(sDelegate(255)); } } 2.9.3 Комбинированные делегаты По своей структуре комбинированные делегаты — это связный список делегатов с возвращаемым типом void. Вообще любой делегат, с возвращаемым типом void является комбинированным, даже если представляет связный список с одним элементом. Комбинированные делегаты наследуются от System.MulticastDelegate. Комбинированные делегаты могут соединяться с помощью статического метода Combine класса System.Delegate: public static Delegate Combine(Delegate[]); // комбинирует массив делегатов public static Delegate Combine(Delegate, Delegate); // комбинирует два делегата 55 Для удаления делегата из связного списка существует статический метод Remove класса System.Delegate: public static Delegate Remove(Delegate source, Delegate value); где source — связный список делегатов, value — удаляемый делегат. Комбинирование и удаление делегата также можно осуществлять с помощью перегруженных операторов += и –= соответственно. Приведем пример использования комбинированных делегатов. using System; public delegate void sampleDelegate(int x); public class DelegateClass1 { public void sampleMethod(int x) { Console.WriteLine(x – 2); } } public class DelegateClass2 { public void sampleMethod(int x) { Console.WriteLine(x + 2); } } public class UseDelegates { public static void Main(String[] args) { DelegateClass1 dc1 = new DelegateClass1(); DelegateClass2 dc2 = new DelegateClass2(); // Создаем экземпляры делегатов sampleDelegate sDelegate1 = new sampleDelegate(dc1.sampleMethod); sampleDelegate sDelegate2 = new sampleDelegate(dc2.sampleMethod); sampleDelegate sdCombination; // Создаем комбинированный делегат sdCombination = (sampleDelegate)Delegate.Combine(sDelegate1, sDelegate2); 56 sdCombination(3); } } Здесь вызовы sDelegate1 и sDelegate2 объединяются в sdCombination, а затем вызывается полученная комбинация. Получить массив делегатов, скомбинированных в один делегат sdCombination можно с помощью метода GetInvocationList(). Delegate[] sDelegates; sDelegates = sdCombination.GetInvocationList(); 2.9.4 Использование делегатов Делегаты могут использоваться для вызова как статических, так и нестатических функций. Например: delegate void D(int x); class C { public static void M1(int i) {...} public void M2(int i) {...} } class Application { static void Main() { D cd1 = new D(C.M1); C test = new C(); D cd2 = new D(test.M2); метод } } // статический метод // нестатический Вызов делегатов, указывающих на нестатические функции, производится через объект класса. 57 2.10 События Наиболее логичным применением делегатов является обработка событий. Если в типе определен член-событие, то этот тип или (его экземпляр) может уведомлять другие объекты о некоторых особых событиях. Например, класс Button (“кнопка”) определяет событие Click (“щелчок”). В приложении могут быть объекты, которые должны получать уведомление о щелчке объекта Button, и, получив такое уведомление, исполнять некоторые действия. События — это члены типа, обеспечивающие такого рода взаимодействие. 2.10.1 Объявление События объявляются с помощью ключевого слова event. public delegate System.EventArgs e); void EventHandler(object sender, public class Button { public event EventHandler Click; public void Reset() { Click = null; } } 2.10.2 Генерация событий Функциональные возможности события представлены тремя взаимодействующими элементами: класс, который предоставляет дополнительную информацию, передаваемую получателям уведомления о событии, делегат события, и класс, который генерирует событие. Чтобы вызвать событие по имени EventName, необходимо создать следующие элементы. 1. 2. 3. Класс, который содержит данные события, именованный EventNameEventArgs. Этот класс должен происходить от System.EventArgs. Делегат, определяющий прототип метода, который будет вызван при срабатывании события. Согласно принятым правилам имя делегата должно заканчиваться словом EventHandler, а сам он должен иметь возвращаемое значение типа void и принимать два параметра: object — ссылка на объект, присылающий уведомление; тип, производный от EventArgs, содержащий любую дополнительную информацию, необходимую получателям уведомления. Событие. 58 4. 5. Защищенный виртуальный метод, ответственный за уведомление зарегистрированных объектов о событии. Метод, транслирующий входную информацию в желаемое событие Для подписки на события используется оператор +=, для её отмены — оператор –=. using System; public class SampleForm { private Button SampleButton; public SampleForm () { SampleButton = new Button(); SampleButton.Click += new EventHandler(SampleButton_Click); } void SampleButton_Click(object sender, EventArgs e) { Console.WriteLine("Кнопка нажата!"); } public void Disconnect() { SampleButton.Click –= new EventHandler(SampleButton_Click); } } 2.11 Атрибуты Атрибуты позволяют добавлять любую дополнительную текстовую информацию о ваших классах, методах, полях, свойствах и т.д. Атрибуты сохраняются вместе с метаданными (metadata) и могут быть достаточно просто получены во время выполнения программы при помощи процесса называемого reflection. 2.11.1 Типы данных допустимые в атрибутах Атрибут может содержать поля следующих типов: bool byte char double float int long short 59 string object System.Type открытые перечислимые типы одномерные массивы из перечисленных выше типов Попытка использовать в классе, реализующем атрибут, другие типы приводит к ошибкам компиляции. 2.11.2 Объявление Атрибутивные классы должны объявляться как открытые. По соглашению имена классов должны заканчиваться словом Attribute. Хотя это и необязательно, рекомендуется поступать так для улучшения читаемости текста. При использовании атрибута это слово необязательно. Все атрибутивные классы должны наследоватьcя от System.Attribute. Атрибутивные классы должны иметь атрибут AttributeUsageAttribute, обозначающий область применения (языковые элементы). Если атрибут не указан, используется значение по умолчанию (п. 3.9.8). Например: // Этот атрибут может применяться только к методам [AttributeUsage(AttributeTargets.Method)] public class MethodsAttribute: System.Attribute { // ... } 2.11.3 Конструктор Атрибуты инициализируются конструкторами, так же как обычные классы. Следующий фрагмент кода иллюстрирует типичный конструктор атрибута. Этот открытый конструктор принимает один параметр и инициализирует переменную класса. public SampleAttribute(bool bool_value) { this.bool_value = bool_value; } Конструкторы можно перегружать, чтобы принимать различные комбинации параметров. Если для атрибутивного класса определены свойства, для инициализации можно использовать комбинацию позиционных и именованных параметров. Обычно все обязательные параметры объявляются как позиционные, а необязательные как именованные. 60 Примеры использования параметризованного конструктора для инициализации атрибута (предполагается, что атрибут имеет обязательный параметр типа Boolean и необязательный типа String). // Один обязательный (позиционный) и один необязательный (именованный) // параметры. [SampleAttribute(false, OptionalParameter = "дополнительные данные")] // Один обязательный (позиционный) параметр. [SampleAttribute(false)] Параметры, определенные как свойства, могут передаваться в произвольном порядке. Но обязательные параметры должны передаваться в том порядке, в котором они описаны в конструкторе. Следующий фрагмент кода показывает, как необязательный параметр может передаваться перед обязательным. // Именованный параметр помещается перед позиционным. [MyAttribute(OptionalParameter = "дополнительные данные", false)] 2.11.4 Свойства Свойства определяются, если нужно передавать именованные параметры в конструкторы или легко и удобно получать значения полей атрибута. Следующий пример показывает, как реализовать простое свойство для пользовательского атрибута: public bool BoolProperty { get { return this.bool_value; } set { this.bool_value = value; } } 2.11.5 Применение атрибутов Большинство атрибутов применяется к таким элементам языка как классы, методы, поля и свойства. Но некоторые атрибуты являются глобальными — они воздействуют на всю сборку или модуль. Глобальные атрибуты в текстах программ объявляются после using-директив верхнего уровня перед определениями типов и пространств имен. Они могут использоваться в разных исходных файлах одной программы. 2.11.5.1 Применение атрибутов на уровне классов и методов 61 Атрибуты в программном коде используются следующим образом: 1. Определяется новый или берется существующий в .NET Framework атрибут. 2. Инициализируется конкретный экземпляр атрибута с помощью вызова конструктора атрибута. Атрибут помещается в метаданные при компиляции кода и становится доступен CLR и любым инструментальным средствам и приложениям через механизмы рефлексии. По соглашению имена всех атрибутов оканчиваются словом Attribute. Однако, язык C#, не требуют задания полного имени атрибута. Например, если нужно инициализировать атрибут System.ObsoleteAttribute, достаточно написать Obsolete. Следующий пример показывает, как использовать атрибут System.ObsoleteAttribute, помечающий код как устаревший. Атрибуту передается строка «Будет удалено в следующей версии». Этот атрибут заставляет компилятор выдать переданную строку как предупреждение при попытке использования помеченного кода. using System; public class Application { public static void Main() { // На этой строке компилятор выдаст предупреждение. int i = Add(2, 2); } // Этот атрибут применяется только к методу Add. [Obsolete("В следующей версии метод будет удален")] public static int Add(int a, int b) { return (a + b); } } 2.11.5.2 Применение атрибутов на уровне сборок Для применения атрибутов на уровне сборок используется идентификатор assembly. Следующий пример показывает, как используется атрибут AssemblyNameAttribute: using System.Reflection; [assembly: AssemblyName("Драйвер_устройства")] 62 2.11.5.3 Применение атрибутов на уровне модулей Для применения атрибутов на идентификатор module вместо assembly. уровне модулей используется 2.11.6 Специализированные атрибуты В разных пространствах имен .NET определено множество готовых к использованию атрибутов. Многие из них предназначены для организации взаимодействия COM/.NET, отладки и других аспектов в создании приложений .NET. Несколько встроенных атрибутов представлено в следующей таблице: Таб. 3.3 Атрибут Встроенные атрибуты Назначение CLSCompliant Определяет совместимость всех типов сборки с Common Language Specification (CLS). Является эквивалентом атрибута [oleautomation] в IDL. DllImport Для вызова традиционных файлов dll в операционной системе. StructLayout Для определения внутреннего представления структуры. DispID Определяет DISPID для члена в интерфейсе COM. Serializable Помечает класс или структуру как сериализуемые (например, доступные для сохранения на диске и восстановления с него). Помечает поля сериализуемых классов или структур как несериализуемые. NonSerialized К примеру, атрибут DllImport используется, чтобы указать, что метод класса импортируется из Dll. using System.Runtime.InteropServices; public class AppMain { [DllImport("user32.dll")] public static extern int MessageBoxA(int handle, string message, string caption, int flags); public static void Main() { MessageBoxA(0, "Hello World!", "Native Message Box", 0); 63 } } CLR позволяет применять атрибуты практически ко всему, что может быть представлено метаданными. Чаще всего атрибуты применяются к элементам таблиц определений TypeDef (классы, структуры, перечисления, интерфейсы и делегаты), MethodDef (конструкторы), ParamDef, FieldDef, PropertyDef, EventDef, AssemblyDef и ModuleDef. Реже атрибуты применяются к ссылочным таблицам AssemblyDef, ModuleDef, TypeDef и MemberDef. Кроме того, специализированные атрибуты могут применяться к таким элементам метаданных, как права доступа, экспортируемые типы и ресурсы. С# позволяет задавать префикс, указывающий сущность, к которой применяется атрибут. // Возможные префиксы: [assembly: MyAttribute(1)] // Применяется к сборке [module: MyAttribute(2)] // Применяется к модулю [type: MyAttribute(3)] // Применяется к типу class SomeType { [property: MyAttribute(4)] // Применяется свойству public String SomeProp { get { return null; } } к [event: MyAttribute(5)] // Применяется к событию public event EventHandler SomeEvent; [field: MyAttribute(6)] public Int32 SomeField = 0; // Применяется к полю [return: MyAttribute(7)] // Применяется к возвращаемому значению [method: MyAttribute(8)] // Применяется к методу public Int32 SomeMethod( [param: MyAttribute(9)] // Применяется к параметру Int32 SomeParam) { return SomeParam; } } При применении нескольких атрибутов к одной сущности порядок атрибутов не имеет значения. В С# каждый атрибут может быть заключен в квадратные скобки, или несколько атрибутов, разделенных запятыми, перечисляются в одних квадратных скобках. Необязательными являются суффикс Attribute и круглые скобки, если конструктор типа не имеет параметров. Возможные способы применения атрибутов: [Serializable][Flags] 64 [Serializable, Flags] [FlagsAttribute, SerializableAttribute] [FlagsAttribute()][Serializable()] 2.11.7 Определение собственного атрибута В этом разделе объединяется вся предыдущая информация и показывается, как создать простой атрибут, документирующий некоторый фрагмент кода. Атрибут из этого примера содержит информацию об имени и уровне программиста, а также о времени последнего пересмотра кода. Он содержит три закрытых переменных, в которых хранятся данные. Каждая переменная связана с открытым свойством для чтения и записи значений. Также имеется конструктор с двумя обязательными параметрами. [AttributeUsage(AttributeTargets.All)] public class DeveloperAttribute : System.Attribute { // Закрытые поля. private string name; private string level; private bool reviewed; // Конструктор принимает два обязательных параметра: имя и уровень. public DeveloperAttribute(string name, string level) { this.name = name; this.level = level; this.reviewed = false; } // Свойство Name. // Только для чтения. public virtual string Name { get { return name; } } // Свойство Level. // Только для чтения. public virtual string Level { get { return level; } } // Свойство Reviewed. // Чтение / Запись. public virtual bool Reviewed { get { return reviewed; } set { reviewed = value; } 65 } } При создании атрибута в C# необходим предопределенный атрибут — AttributeUsage.(3.9.8) Он задает элементы кода, к которым применим атрибут (в данном случае методы), а также некоторые свойства атрибута. Например, может ли быть атрибут примененным несколько раз к одному элементу. Применять этот атрибут можно, используя как полное имя DeveloperAttribute, так и сокращенное — Developer. [Developer("Василий Пупкин", "1")] [Developer("Василий Пупкин", "1", Reviewed = true)] 2.11.8 Использование атрибута AttributeUsageAttribute Атрибут AttributeUsageAttribute позволяет указать компилятору, где допускается применение вашего специализированного атрибута. У типа AttributeUsageAttribute есть конструктор, позволяющий передавать параметры: один или несколько, приведенных ниже, элементов перечисления AttributeTarget; именованный аргумент AllowMultiple (необязательный), который определяет, может ли этот аргумент применяться к одному и тому же типу несколько раз; параметр Inherited типа bool (необязательный), определяет должен ли этот атрибут наследоваться производными классами. namespace System { [AttributeUsage(AttributeTargets.Class)] public class AttributeUsageAttribute: Attribute { public AttributeUsageAttribute(AttributeTargets validOn) {...} public virtual bool AllowMultiple { get {...} set {...} } public virtual bool Inherited { get {...} set {...} } public virtual AttributeTargets ValidOn { get {...} } } public enum AttributeTargets { Assembly = 0x0001, Module = 0x0002, Class = 0x0004, Struct = 0x0008, Enum = 0x0010, 66 Constructor = 0x0020, Method = 0x0040, Property = 0x0080, Field = 0x0100, Event = 0x0200, Interface = 0x0400, Parameter = 0x0800, Delegate = 0x1000, ReturnValue = 0x2000, All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate| ReturnValue } } 2.11.9 Доступ к информации, хранящейся в атрибутах Получение информации, содержащейся в атрибутах, осуществляется с помощью механизма, который называется отражением (Reflection). 2.11.9.1 Получение одиночного атрибута В следующем примере атрибут DeveloperAttribute применяется к классу MainApp в целом. Метод GetAttribute использует Attribute.GetCustomAttribute для получения состояния атрибута DeveloperAttribute перед тем, как вывести информацию на консоль. using System; [Developer("Василий Пупкин", "42", Reviewed = true)] class MainApp { public static void Main() { // Вызвать функцию получения и отображения атрибута. GetAttribute(typeof(MainApp)); } public static void GetAttribute(Type t) { // Получить атрибут. DeveloperAttribute MyAttribute = (DeveloperAttribute)Attribute.GetCustomAttribute(t, typeof(DeveloperAttribute)); if(MyAttribute == null) { 67 Console.WriteLine("Атрибут не найден"); } else { // Получить поле Имя. Console.WriteLine("Имя: {0}", MyAttribute.Name); // Получить поле Уровень. Console.WriteLine("Уровень: {0}", MyAttribute.Level); // Получить поле Проверено. Console.WriteLine("Проверено: {0}", MyAttribute.Reviewed); } } } При запуске эта программа выдает на консоль следующие строки: Имя: Василий Пупкин Уровень: 42 Проверено: True Если атрибут не найден, метод GetCustomAttribute возвращает нулевое значение. В этом примере предполагается, что атрибут определен в текущем пространстве имен, если это не так, не забудьте импортировать соответствующее пространство имен. 2.11.9.2 Получение списка однотипных атрибутов В предыдущем примере ссылки на класс и атрибут передавались в метод GetCustomAttribute. Этот код прекрасно работает, если на уровне класса определен только один атрибут. Но если на том же уровне определено несколько однотипных атрибутов, этот метод вернет не всю информацию. В таких случаях нужно использовать метод Attribute.GetCustomAttributes, который возвращает массив атрибутов. Например, если на уровне класса определены два экземпляра атрибута DeveloperAttribute, можно модифицировать метод GetAttribute, чтобы получить оба. Разумеется, для многократного задания атрибута DeveloperAttribute он должен быть объявлен с AttributeUsage(AttributeTargets.All, AllowMultiple = true). public static void GetAttribute(Type t) { // Получить атрибут. DeveloperAttribute [] MyAttribute = (DeveloperAttribute [])Attribute.GetCustomAttributes(t, typeof(DeveloperAttribute)); 68 if(MyAttribute == null) Console.WriteLine("Атрибут не найден"); else for (int i = 0; i < MyAttribute.Length; i++) { // Получить поле Имя. Console.WriteLine("Имя: {0}", MyAttribute[i].Name); // Получить поле Уровень. Console.WriteLine("Уровень: {0}", MyAttribute[i].Level); // Получить поле Проверено. Console.WriteLine("Проверено: {0}", MyAttribute[i].Reviewed); } } 2.11.9.3 Получение списка разнотипных атрибутов Методы GetCustomAttribute и GetCustomAttributes не могут искать атрибут во всем классе и возвращать все его экземпляры. Они просматривают только один метод или поле за раз. Поэтому, если есть класс с одним атрибутом для всех методов и нужно получить все экземпляры этого атрибута эти методы передаются один за другим в качестве параметров GetCustomAttribute и GetCustomAttributes. В следующем фрагменте кода показано, как получить все экземпляры атрибута DeveloperAttribute, определенного как на уровне класса, так и на уровне методов. using System; using System.Reflection; public static void GetAttribute(Type t) { // Получить атрибут уровня класса. DeveloperAttribute att = (DeveloperAttribute) Attribute.GetCustomAttribute(t, typeof(DeveloperAttribute)); if(att == null) Console.WriteLine("Класс {0} не имеет атрибута Developer\n", t.ToString()); else { Console.WriteLine("Атрибут Имя на уровне класса: {0}", att.Name); Console.WriteLine("Атрибут Уровень на уровне класса: {0}", att.Level); Console.WriteLine("Атрибут Проверено на уровне класса: {0}\n", att.Reviewed); } // Получить все методы данного класса и поместить их 69 // в массив объектов System.Reflection.MemberInfo. MemberInfo [] MyMemberInfo = t.GetMethods(); // Вывести атрибуты всех методов класса for(int i = 0; i < MyMemberInfo.Length; i++) { att = (DeveloperAttribute)Attribute.GetCustomAttribute(MyMemberInfo[i], typeof(DeveloperAttribute)); if(att == null) Console.WriteLine("Метод {0} не имеет атрибута Developer\n" , MyMemberInfo[i].ToString()); else { Console.WriteLine("Атрибут Имя на уровне метода {0}: {1}", MyMemberInfo[i].ToString(), att.Name); Console.WriteLine("Атрибут Уровень на уровне метода {0}: {1}", MyMemberInfo[i].ToString(), att.Level); Console.WriteLine("Атрибут Проверено на уровне метода {0}: {1}\n", MyMemberInfo[i].ToString(), att.Reviewed); } } } Для доступа к методам и полям проверяемого класса используются методы класса System.Type. В этом примере сначала через Type запрашивается информация об атрибутах, определенных на уровне класса, затем, через метод Type.GetMethods получается информация обо всех атрибутах, определенных на уровне методов. Эта информация помещается в массив объектов типа System.Reflection.MemberInfo. Если нужны атрибуты свойств, используется метод Type.GetProperties, а для конструкторов — Type.GetConstructors. Класс Type имеет множество методов для доступа к элементам типа, здесь описана только очень небольшая часть. 2.12 Исключения Исключения в C# предоставляют структурированный, единообразный и типобезопасный способ обработки некорректных состояний (ошибок) как на системном уровне, так и на уровне приложений. Исключение представляет собой экземпляр класса, производного от System.Exception, их использование сходно с подобным механизмом в C++. При генерации исключения выполнение текущего блока прекращается; и идет возврат управления на более высокий уровень. На нем исключение может быть «поймано» и обработано; 70 если же этого не произошло, осуществляется переход еще выше и т. д., пока не будет достигнут самый верхний уровень, в котором обрабатываются все исключения. Синтаксис в общем случае выглядит следующим образом: try { блок команд, в котором может возникнуть ошибка } catch [(тип_исключения имя_исключения)] { блок обработки исключения } finally { команды, которые выполняются в любом случае — после блоков try и catch } В приведенной конструкции один из блоков: catch или finally — может отсутствовать. Если отсутствует блок catch, исключение будет обрабатываться на более высоких уровнях (после выполнения блока finally). Возможно использование нескольких блоков catch: для обработки различных типов исключительных ситуаций. Схема работы такой конструкции очень проста — если в блоке try происходит исключение, то происходит переход на блок catch, сгенерированное исключение передается в качестве параметра. В любом случае (произошло исключение или нет) в конце вызывается блок команд finally. Если в блоке catch не указан параметр (тип исключения), в нем будет обрабатываться любая исключительная ситуация. 2.12.1 Генерация и перехват исключения Чтобы сгенерировать исключение необходимо создать новый объект класса Exception или производного от него. Для передачи этого объекта используется ключевое слово throw. class ReverseFunction { public static double Calculate(double d) { if (d == 0) throw new Exception("Функция не определена для нулевого значения"); return 1/d; 71 } public static void Main() { try { Console.WriteLine("1 / {0} = {1}", 1, Calculate(1)); Console.WriteLine("1 / {0} = {1}", 2, Calculate(2)); Console.WriteLine("1 / {0} = {1}", 0, Calculate(0)); } catch (Exception e) { Console.WriteLine("Ошибка! {0}", e); } } } Перехват исключения осуществляется в блоке try/catch. При возникновении исключения выполнение кода, определенного в блоке try, прерывается, и начинает выполняться код, определенный в ближайшем следующем блоке catch. Если же в процессе выполнения кода в блоке try исключений так и не возникло, блок catch полностью пропускается и выполнение программы идет дальше согласно ее внутренней логике. Несколько блоков catch используются в том случае, когда для разных типов исключений необходимо выполнять различные действия. При этом выполняется первый блок catch, соответствующий типу сгенерированного исключения. try { CalculateSpline(); } catch (DivisionByZeroException e) { Console.WriteLine("Деление на ноль"); } catch (OverflowException e) { Console.WriteLine("Переполнение"); } catch (Exception e) // Обработка остальных типов исключения { Console.WriteLine("Ошибка! {0}", e); } 72 2.13 Директивы препроцессора В C# перед компиляцией код обрабатывается специальной программой — препроцессором. Препроцессор ищет в коде специальные директивы и в соответствии с ними изменяет код. Часто подобные директивы выделяют блоки кода и позволяют условно включать или исключать их из компиляции. Для внешней параметризации препроцессора используются определения. Для каждого определения (которое однозначно определяется своим именем) можно сказать, что оно либо определено, либо нет; в зависимости от этого препроцессор выполняет различные действия. Определения можно задаются с помощью директивы #define, которая имеет следующий вид. #define имя_определения После этой директивы определение с данным именем считается определенным. Определение можно снять с помощью директивы #undef. #undef имя_определения Использование директив #define и #undef возможно только в начале кода — до любых языковых инструкций (за исключением директив препроцессора). Область видимости определения — файл, в котором оно задано. В отличие от C++, где директива #define использовалась для задания макросов: фрагментов кода или значений констант, в C# она предназначена лишь для определения символов. C помощью определений символов можно контролировать исключение блоков кода из компиляции. Для этого используется условная компиляция: директивы #if, #else, #elif и #endif. Общий вид такого блока следующий. #if выражение1 ... #elif выражение2 ... #elif выражениеk ... #else ... #endif Блоки #elif и #else могут отсутствовать. Выражение — это логическое выражение, в котором термами являются имена определений, а их истинностным значением — их определенность. Таким образом, если выражение верно, то выполняется соответствующий блок. #define DEBUG #define VC_V7 73 using System; public class MyClass { public static void Main() { #if (DEBUG && !VC_V7) Console.WriteLine("Определен символ DEBUG"); #elif (!DEBUG && VC_V7) Console.WriteLine("Определен символ VC_V7"); #elif (DEBUG && VC_V7) Console.WriteLine("Определены символы DEBUG и VC_V7"); #else Console.WriteLine("Не определены ни символ DEBUG, ни символ VC_V7"); #endif } } Еще одной группой директив являются директивы, контролирующие генерацию ошибок. Это директивы #error, #warning и #line. Их синтаксис таков: #error текст #warning текст Если компилятор встречает директиву #error или #warning, он генерирует ошибку или предупреждение с соответствующим текстом. #define DEBUG public class MyClass { public static void Main() { #if DEBUG #error DEBUG is defined #endif } } #define DEBUG public class MyClass { public static void Main() { #if DEBUG #warning DEBUG is defined #endif } } 74 Директива #line позволяет переопределить имя файла или номер строки, которые будут выводиться при ошибках. Значение default восстанавливает оригинальную нумерацию. Значение hidden приводит к игнорированию строк кода отладчиком. #line номер_строки ["имя_файла"] #line default #line hidden В приведенном примере компилятор сгенерирует два предупреждения «Переменная объявлена, но не используется»: на строках 8 и 200. public class MyClass { public static void Main() { #line 200 int i; // строка 200 #line default char c; // строка 8 } } Директивы #region и #endregion выделяют блок кода в регион. Регионы удобны при работе в среде Visual Studio: редактор позволяет «сворачивать» их в одну строчку, что облегчает чтение кода. #region имя_региона #endregion Допустимо многократное вложение регионов друг в друга. Блоки #region..#endregion и #if..#endif могут быть вложены один в другой, но не могут перекрываться. #region Объявление класса MyClass public class MyClass { public static void Main() { … } } #endregion 75 3. Встроенные элементы 3.1 Класс System.Math Предоставляет константы и статические методы для тригонометрических, логарифмических, и других общих математических функций. Все статические члены класса являются потокобезопасными. 3.1.1 Методы public static decimal Abs(decimal value) public static double Abs(double value) public static int Abs(int value) public static long Abs(long value) public static float Abs(float value) public static sbyte Abs(sbyte value) public static short Abs(short value) Описание: Вычисляет абсолютное значение указанного числа. Метод переопределен для разных типов значения (decimal, double, short, int, long, float, sbyte). Параметры: value – число в диапазоне MinValue≤value≤MaxValue; где: MaxValue – максимально допустимое значение используемого типа; MinValue – максимально допустимое значение используемого типа. Возвращает: Возвращает абсолютное значение указанного числа – х, 0≤ х≤ MaxValue. Замечаниe: В случае работы метода с типами float и double, если value равно NegativeInfinity(см. глоссарий) или PositiveInfinity, возвращаемое значение равно PositiveInfinity, если value равно NaN – возвращаемое значение равно NaN; Исключение: В случае работы метода с типами: short — генерируется исключение OverflowException, при условии value=MaxValue; int, long, sbyte — генерируется исключение OverflowException, при условии value=MinValue. 76 public static double Acos(double d); Описание: Вычисляет угол, косинус которого — указанное число. Параметры: d — значение косинуса; -1 ≤ d ≤ 1. Возвращает: Угол θ, измеряемый в радианах; 0 ≤ θ ≤ π или θ =NaN, если d <-1 или d> 1. public static double Asin(double d); Описание: Вычисляет угол, синус которого — указанное число. Параметры: d — значение синуса; -1 ≤ d ≤ 1. Возвращает: Угол θ, измеряемый в радианах; п/2 ≤ θ ≤ п/2 или θ =NaN, если d <-1 или d> 1. public static double Atan(double d); Описание: Вычисляет угол, тангенс которого — указанное число. Параметры: d - значение тангенса; -1 ≤ d ≤ 1. Возвращает: Угол θ, измеряемый в радианах; -п/2 ≤ θ ≤ п/2 или: θ=NaN, если d =NaN; θ=-п/2, если d=NegativeInfinity; θ= п/2, если d=PositiveInfinity. public static double Atan2(double y, double x); Описание: Вычисляет угол, тангенс которого — частное двух заданных чисел. Параметры: y — координата точки по оси Oy; x — координата точки по оси Ox; Возвращает: 77 Угол θ, измеряемый в радианах; -п ≤ θ ≤ п, а tan(θ)=y/x, где (х,y) — точка в декартовой системе координат. Причем θ изменяется в зависимости от того, в каком квадранте находится точка (x, y): в 1-ом квадранте, 0 <θ <π/2; во 2-ом квадранте, π/2 <θ ≤ π; в 3-ем квадранте, - π <θ <-π/2; в 4--ом квадранте, - π/2 <θ <0. public static double Ceiling(double a); Описание: Округляет заданное число а до наименьшего целого, большего или равного а. Параметры: а – число. Возвращает: Наименьшее целое число, большее или равное a (округление в бóльшую сторону). public static double Cos(double d); Описание: Вычисляет косинус указанного угла. Параметры: d – угол, измеряемый в радианах. Если угол d указан в градусах, необходимо перевести его в радианы – d(рад)=d(град)*п/180. Возвращает: Косинус d. public static double Cosh(double value); Описание: Вычисляет гиперболический косинус указанного угла. Параметры: value – угол, измеряемый в радианах. Если угол value указан в градусах, необходимо перевести его в радианы – value(рад)= value(град)*п/180. Возвращает: Гиперболический косинус value. Если value равно NegativeInfinity или PositiveInfinity, то возвращаемое значение равно PositiveInfinity. Если value равно NaN, то возвращаемое значение равно NaN. public static int DivRem (int a, int b, out int result); 78 public static long DivRem (long a, long b, out long result); Описание: Вычисляет частное двух чисел, передавая остаток как выходной параметр. Метод переопределен для разных типов значения (int, long). Параметры: a – делимое; b – делитель; result – полученный остаток. Возвращает: Частное двух чисел – result типа int или long, в зависимости от того, с каким типом работает данный метод. public static double Exp(double d); Описание: Вычисляет значение числа е в заданной степени. Параметры: d – число, определяющее степень. Возвращает: Число е, возведенное в степень d. Если d=NaN или d=PositiveInfinity, возвращаемое значение совпадает с d; если d=NegativeInfinity, возвращаемое значение равно нулю. public static double Floor(double d); Описание: Округляет заданное число d до наибольшего целого, меньшего или равного d. Параметры: d – число. Возвращает: Наибольшее целое число, меньшее или равное a (округление в меньшую сторону). public static double Log(double d); public static double Log(double d, double NewBase); Описание: 79 Вычисляет логарифм заданного числа. Метод, так же, переопределен для вычисления логарифма по заданному основанию. Параметры: d – число, логарифм которого должен быть вычислен. NewBase – основание логарифма. Возвращает: Если метод применяется для вычисления логарифма заданного числа: Значение d Возвращаемое значение Положительное Натуральный логарифм d; то есть ln d Нуль NegativeInfinity Отрицательное NaN Если параметр d равен NaN, возвращается NaN. Если d равен PositiveInfinity, возвращается PositiveInfinity. Если метод применяется для вычисления логарифма заданного числа, по заданному основанию: Значение d Возвращаемое значение Положительное Если NewBase ≥ 0, возвращается логарифм по основанию NewBase. Иначе, NaN. Нуль NegativeInfinity Отрицательное NaN Если параметр d равен PositiveInfinity , и NewBase не равен PositiveInfinity, NegativeInfinity, или NaN, метод возвращает PositiveInfinity. Если NewBase равен PositiveInfinity, и d не равен PositiveInfinity, NegativeInfinity, или NaN, метод возвращается 0. Если оба параметра, и d и NewBase равны PositiveInfinity, или d, или NewBase равен NaN или NegativeInfinity, метод возвращает NaN. Если оба параметра, и d и NewBase равны PositiveInfinity, или d, или newBase равен NaN или NegativeInfinity, метод возвращает NaN. public static double Log10(double d); 80 Описание: Вычисляет десятичный логарифм заданного числа. Параметры: d – число, логарифм которого должен быть вычислен. Возвращает: Значение d Возвращаемое значение Положительное Десятичный логарифм числа d, т.е. lg d . Нуль NegativeInfinity Отрицательное NaN Если параметр d равен NaN, метод возвращает NaN. Если d равен PositiveInfinity, метод возвращает PositiveInfinity. public static byte Max(byte val1, byte val2) public static decimal Max(decimal val1, decimal val2) public static double Max(double val1, double val2) public static short Max(short val1, short val2) public static int Max(int val1, int val2) public static long Max(long val1, long val2) public static sbyte Max(sbyte val1, sbyte val2) public static float Max(float val1, float val2) public static ushort Max(ushort val1, ushort val2) public static uint Max(uint val1, uint val2) public static ulong Max(ulong val1, ulong val2) Описание: Возвращает большее из двух заданных чисел. Метод переопределен для разных типов значения (byte, short, int, long, float, double, Decimal, sbyte, ushort, uint, ulong). Параметры: Val1 — первое число; Val2 — второе число. Возвращает: Большее из двух чисел – Val1 или Val2. public static byte Min(byte val1, byte val2) public static decimal Min(decimal val1, decimal val2) 81 public static double Min(double val1, double val2) public static short Min(short val1, short val2) public static int Min(int val1, int val2) public static long Min(long val1, long val2) public static sbyte Min(sbyte val1, sbyte val2) public static float Min(float val1, float val2) public static ushort Min(ushort val1, ushort val2) public static uint Min(uint val1, uint val2); public static ulong Min(ulong val1, ulong val2) Описание: Возвращает меньшее из двух заданных чисел. Метод переопределен для разных типов значения (byte, short, int, long, float, double, Decimal, sbyte, ushort, uint, ulong). Параметры: Val1 — первое число; Val2 — второе число. Возвращает: Меньшее из двух чисел – Val1 или Val2. public static double Pow(double x, double y); Описание: Возводит заданное число в заданную степень. Параметры: х – основание степени — число, которое будет возведено в степень; y – показатель степени. Возвращает: Число х в степени y. Следующая таблица указывает возвращаемое значение, при различных значениях или диапазонах значений, определенных для x и y параметров. Параметры x или y = NaN Любое значение x кроме NaN; y = 0 x = NegativeInfinity; y <0 x = NegativeInfinity; y - положительное нечетное целое число x = NegativeInfinity; y - не 0 или положительное нечетное целое число x <0; (-1 <y <0) или (0 <y <1) x <-1; y = NegativeInfinity x <-1; y = PositiveInfinity x =-1; y = NegativeInfinity или 82 Возвращаемое значение NaN 1 0 NegativeInfinity PositiveInfinity NaN 0 PositiveInfinity NaN PositiveInfinity (0> = x>-1); y = NegativeInfinity (0> = x>-1); y = PositiveInfinity x = 0; y <0 x = 0; y> 0 (0 <x <1); y = NegativeInfinity (0 <x <1); y = PositiveInfinity x - 1; y - любое значение кроме NaN x> 1; y = NegativeInfinity x> 1; y = PositiveInfinity x = PositiveInfinity; y <0 x = PositiveInfinity; y> 0 PositiveInfinity 0 PositiveInfinity 0 PositiveInfinity 0 1 0 PositiveInfinity 0 PositiveInfinity public static decimal Round(decimal d) public static double Round(double d) public static decimal Round(decimal d, int value) public static double Round(double d, int value) Описание: Округляет заданное число, до указанного количества знаков (или до целого). Метод переопределен для типов decimal и double. Параметры: d – заданное число; value – число значащих цифр в возвращаемом значении, т. е. заданная точность. Возвращает: Если метод используется без заданной точности, то возвращается значение d, округленное до ближайшего целого числа. Причем, если значение d находится на половине между двумя целыми числами, то возвращается четное число. Если метод используется с заданной точностью, то возвращается число, самое близкое к числу d с заданной точностью value. Причем, если значение d находится на середине между двумя числами, то возвращается четное число. Если точность d меньше value, то d возвращается без изменений. Замечание: Если метод используется для округления значения типа decimal, то value может изменяться в пределах от 0 до 28. При value=0 возвращается целое число. Если метод используется для округления значения типа double, то value может изменяться в пределах от 0 до 15. Исключение: ArgumentOutOfRangeException – генерируется при value<0, value>15, если метод используется для округления значения типа double. 83 public static int Sign(decimal value) public static int Sign(double value) public static int Sign(short value) public static int Sign(int value) public static int Sign(long value) public static int Sign(sbyte value) public static int Sign(float value) Описание: Используется для определения знака заданного числа. Метод переопределен для разных типов значения (decimal, double, short, int, long, sbyte, float). Параметры: value – число, знак которого необходимо определить. Возвращает: Значение -1 0 1 Описание value<0 value=0 value>0 Исключение: ArithmeticException – генерируется, при value=NaN, если заданное число value типа double или float. public static double Sin(double a); Описание: Вычисляет синус угла, заданного в радианах. Параметры: a – угол, заданный в радианах. Если угол a указан в градусах, необходимо перевести его в радианы – a(рад)=a(град)*п/180. Возвращает: Синус угла а. При a=NaN, a=PositiveInfinity, a=NegativeInfinity – возвращается NaN. public static double Sinh(double value); Описание: Вычисляет гиперболический синус угла, заданного в радианах. 84 Параметры: value – угол, заданный в радианах. Если угол value указан в градусах, необходимо перевести его в радианы – value(рад)=value(град)*п/180. Возвращает: Гиперболический синус угла value. При value =NaN, a=PositiveInfinity, value=NegativeInfinity – возвращается значение, эквивалентное аргументу. public static double Sqrt(double d); Описание: Вычисляет квадратный корень указанного числа. Параметры: d – число. Возвращает: Если d>=0,возвращается положительный корень квадратный из d, если d<0, возвращается NaN. public static double Tan(double a); Описание: Вычисляет тангенс угла, заданного в радианах. Параметры: a – угол, заданный в радианах. Если угол a указан в градусах, необходимо перевести его в радианы – a(рад)=a(град)*п/180. Возвращает: Тангенс угла а. При a=NaN, a=PositiveInfinity, a=NegativeInfinity – возвращается NaN. public static double Tanh(double value); Описание: Вычисляет гиперболический тангенс угла, заданного в радианах. Параметры: value – угол, заданный в радианах. Если угол value указан в градусах, необходимо перевести его в радианы – value(рад)=value(град)*п/180. Возвращает: Гиперболический тангенс угла value. При value=PositiveInfinity, возвращается 1, при value=NegativeInfinity, возвращается –1.Если value=NaN, возвращается NaN. 85 3.1.2 Поля public const double E; Описание: Предоставляет основание натурального логарифма, константой е. Замечание: Значение этого поля – 2.7182818284590452354. указанное public const double Pi; Описание: Предоставляет отношение окружности круга к его диаметру, указанное константой π. Замечание: Значение этого поля - 3.14159265358979323846. 86 3.2 Класс System.Random Предоставляет генератор последовательности псевдослучайных чисел. Числа выбираются из конечного набора с равновероятным распределением. Все статические члены класса являются потокобезопасными; безопасность экземплярных членов не гарантируется. 3.2.1 Методы public virtual bool Equals(object obj); public virtual bool Equals(object obj1, object obj2); Описание: Метод унаследован от класса Object. Определяет, равны ли два экземпляра Object. Метод переопределен и может использоваться для сравнения как текущего объекта с заданным, так и двух заданных объектов. Параметры: В случае, когда сравнение производиться с текущим объектом, методу передается один параметр: obj – объект, который необходимо сравнить с текущим. Если метод применяется для сравнения двух заданных объектов, передается два параметра: obj1, obj2 – объекты которые необходимо сравнить. Возвращает: True, если сравниваемые объекты равны, иначе false. public Type GetType(); Описание: Метод унаследован от класса Object. Получает тип текущего экземпляра. Возвращает: Тип текущего экземпляра. public virtual int Next(); public virtual int Next(int maxValue); public virtual int Next(int minValue, int maxValue); Описание: Возвращает случайное число. Параметры: 1. нет 87 maxValue – верхняя граница сгенерированного случайного числа. maxValue>=0. 3. minValue – нижняя граница сгенерированного случайного числа; maxValue - верхняя граница сгенерированного случайного числа;. maxValue>= minValue. 2. Возвращает: 1. 32-разрядное целое неотрицательное число, меньшее чем MaxValue, где MaxValue – наибольшее значение типа Int32. 2. 32-разрядное целое неотрицательное число, меньшее чем maxValue, где maxValue – заданный параметр. 3. 32-разрядное целое число, большее или равное minValue, но меньшее чем maxValue, где minValue и maxValue – заданные параметры. Если minValue= maxValue – возвращается minValue. Исключение: 1. нет. 2. ArgumentOutOfRangeException, если maxValue<0. 3. ArgumentOutOfRangeException, если maxValue<minValue. public virtual void NextBytes(byte [] buffer); Описание: Заполняет элементы указанного байтового массива случайными числами. Параметры: buffer – байтовый массив. Возвращает: Байтовый массив, элементы которого заполнены случайными числами. Исключение: ArgumentNullException, если buffer – нулевая ссылка. public virtual double NextDouble(); Описание: Возвращает случайное число между 0.0 и 1.0. public virtual string ToString(); 88 Описание: Метод унаследован от Object. Возвращает строковое представление объекта. Возвращает: Строку, представляющую объект. Метод Finalize ~Object(); Описание: Метод, унаследованный от класса Object. Позволяет объекту освободить ресурсы и выполнить другие операции по очистке памяти перед тем как будет вызван сборщик мусора. protected object MemberwiseClone(); Описание: Метод унаследован от класса Object. Создает ограниченную копию текущего объекта. Возвращает: Копию текущего объекта. Замечание: Метод MemberwiseClone не может быть переопределен и доступен только через класс System.Random или производный от него. protected virtual double Sample(); Описание: Возвращает случайное число между 0.0 и 1.0. Конструктор Public Random(); Public Random(int seed); Описание: Инициализирует новый экземпляр класса Random. Метод переопределен и может работать как с параметром, так и без параметра. Параметры: seed – число, задающее начальное значение псевдослучайной последовательности чисел. 89 3.3 Структура DateTime Описывает момент времени, выраженный через дату и время. Далее будут выборочно рассмотрены методы, свойства и конструкторы структуры DateTime. 3.3.1 Методы public string ToLongDateString(); Описание: Используется для преобразования даты в определенный формат. Возвращается: Строка, содержащая день недели, название месяца, число, год. (Например, «Tuesday, June 1, 2004» для английской версии .Net Framework) public string ToShortDateString (); Описание: Используется для преобразования даты в определенный формат. Возвращается: Строка, содержащая числовое представление даты. (Например: 6/1/2004) public string ToLongTimeString(); Описание: Используется для преобразования время суток в определенный формат. Возвращается: Строка, содержащая часы, минуты, секунды. (Например, 8:45:15 AM) public string ToShortTimeString (); Описание: Используется для преобразования время суток в определенный формат. Возвращает: Строка, содержащая часы и минуты. (Например, 8:45) public override string ToString (); 90 public override string ToString (IFormatProvider provider); public override string ToString (string format); public override string ToString (string format, IFormatProvider provider); Описание: Позволяет форматировать дату и время в определенном формате. Параметры: provider – определяет интерфейс. Для этого аргумента необходим экземпляр класса, реализуемый IFormatProvider. format - буква или набор букв, определяющих стиль форматирования. Возвращается: Строка, отформатированная в соответствии с заданными параметрами. Исключения: FormatException – генерируется, если format – не относится к символам, задающим тип форматирования, определенным в DateTimeFormatInfo. public DateTime ToUniversalTime(); Описание: Преобразовывает время к UTC (Universal Универсальное Координированное Время). Возвращает: Значение DateTime, преобразованное к UTC. Coordinated 3.3.2 Свойства public int Year { get;} Описание: Возвращает значение года в интервале от 1 до 9999. public int Moth { get;} Описание: Возвращает значение месяца в интервале от 1 до 12. public int Day { get;} 91 Time, Описание: Возвращает день — число в интервале от 1 до 31. public int Hour { get;} Описание: Возвращает значение часа в интервале от 1 до 12. public int Minute { get;} Описание: Возвращает значение минут в интервале от 0 до 59. public int Second { get;} Описание: Возвращает значение секунд в интервале от 0 до 59. public int Millisecond { get;} Описание: Возвращает значение миллисекунд в интервале от 0 до 999. public int DayOfWeek { get;} Описание: Возвращает значение дня недели от 0 (воскресенье) до 6 (суббота). public int DayOfYear { get;} Описание: Возвращает день года в интервале от 1 до 366. public DateTime Date { get;} Описание: Возвращает дату, т.е. хранящееся в объекте значение, но со временем, установленным в 0:00:00 (полночь). public static DateTime Now {get;} 92 Описание: Текущие местные дата и время. public static DateTime Today {get;} Описание: Текущая местная дата. public static DateTime UtcNow {get;} Описание: Текущие дата и время по UTC. public long Ticks {get;} Описание: Число отсчетов по 100 наносекунд, прошедших с 0:00:00 1.1.0001. public TimeSpan TimeOfDay {get;} Описание: Число отсчетов по 100 наносекунд, прошедших с полуночи. Конструктор DateTime(long ticks); DateTime(int year, int month, int day); DateTime(int year, int month, int day, int hour, int minute, int second); DateTime(int year, int month, int day, int hour, int minute, int second, int msec); DateTime(int year, int month, int day, Calendar cal); DateTime(int year, int month, int day, int hour, int minute, int second, Calendar cal); DateTime(int year, int month, int day, int hour, int minute, int second, int msec,Calendar cal); Описание: Инициализирует новый объект DateTime. Параметры: ticks – число отсчетов времени по 100 наносекунд. year –год в диапазоне от 1 до 9999. 93 month –месяц в диапазоне от 1 до 12. day –дни в диапазоне от 1 до числа дней в соответствующем месяце данного года. hour –количество часов в диапазоне от 0 до 23. minute –количество минут в диапазоне от 0 до 59. second –количество секунд в диапазоне от 0 до 59. msec - количество миллисекунд в диапазоне от 0 до 999. сal – объект типа Calendar. Исключения: ArgumentNullException - генерируется, если Calendar – нулевая ссылка. ArgumentOutOfRangeException – генерируется, если любой из параметров выходит за разрешенные пределы. ArgumentException – генерируется, если указанные параметры выходят за пределы интервала (MinValue, MaxValue). 94 3.4 Структура TimeSpan Описывает интервал времени. Далее будут выборочно рассмотрены свойства и конструкторы структуры TimeSpan. 3.4.1 Свойства public int Days {get;} Описание: Возвращает число дней. public int Hours {get;} Описание: Возвращает число часов от 0 до 23. public int Minutes {get;} Описание: Возвращает число минут от 0 до 59. public int Seconds {get;} Описание: Возвращает количество секунд от 0 до 59. public int Milliseconds {get;} Описание: Возвращает количество миллисекунд от 0 до 999. public long Ticks {get;} Описание: Возвращает число тиков (интервалов по 100 наносекунд). public double TotalDays {get;} 95 Описание: Возвращает значение временного интервала, выраженное в днях (может включать целую и дробную части). public double TotalHours {get;} Описание: Возвращает значение временного интервала, выраженное в часах. public double TotalMinutes {get;} Описание: Возвращает значение временного интервала, выраженное в минутах. public double TotalSeconds {get;} Описание: Возвращает значение временного интервала, выраженное в секундах. public double TotalMilliseconds {get;} Описание: Возвращает миллисекундах. значение временного интервала, выраженное Конструктор TimeSpan(long ticks); TimeSpan (int hours, int minutes, int seconds); TimeSpan (int days, int hours, int minutes, int seconds); TimeSpan (int days, int hours, int minutes, int seconds, int msec); Описание: Инициализирует новый объект TimeSpan. Параметры: ticks – число тиков (отсчетов времени по 100 наносекунд). hour – количество часов. minute – количество минут. 96 в second – количество секунд. msec - количество миллисекунд. Исключения: ArgumentOutOfRangeException – генерируется, если значение объекта TimeSpan выходит за пределы интервала (MinValue, MaxValue). 97 4. Сообщения об ошибках компиляции Код ошибки CS0001 CS0003 CS0004 CS0005 CS0006 CS0007 CS0008 CS0009 CS0010 CS0011 CS0012 CS0013 CS0014 CS0015 CS0016 CS0017 CS0019 CS0020 CS0021 CS0022 CS0023 CS0025 CS0026 CS0027 CS0028 CS0029 CS0030 CS0031 Описание Внутренняя ошибка компилятора Недостаточно памяти Предупреждение рассматривается как ошибка Опции компилятора {0} требуется аргумент Файл метаданных {0} не найден Непредвиденная ошибка инициализации среды выполнения .NET - {0} Непредвиденная ошибка чтения метаданных из файла {0} {1} Метаданные файла {0} не могут быть открыты - {1} Невозможно объявить пространство имен и тип с одинаковым именем {0} Упомянутый класс {0} имеет базовый класс или интерфейс {1}, объявленный в сборке, на которую нет ссылки. Необходимо добавить ссылку на сборку {2} Тип {0} объявлен в сборке, на которую нет ссылки. Необходимо добавить ссылку на сборку {1} Непредвиденная ошибка записи метаданных в файл {0} - {1} Указанный файл {0} не найден Название типа {0} слишком длинное Невозможна запись данных в файл {0} - {1} Программа {0} имеет больше одной точки входа: Оператор {0} не может применяться к операндам типа {1} и {2} Деление на нуль Невозможно применить индексацию при помощи [] к выражению типа {0} Неправильный номер индекса внутри [], ожидаемый номер {} Оператор {0} не может применяться к операнду типа {1} Файл стандартной библиотеки {0} не найден Ключевое слово this нельзя использовать в статическом свойстве, статическом методе или в инициализаторе статического поля Ключевое слово this неприменимо в данном контексте {0} имеет неверную для точки входа сигнатуру Невозможно неявное преобразование типа {0} к {1} Невозможно преобразование типа {0} к {1} Значение константы {0} не может быть преобразовано к типу 98 CS0032 CS0033 CS0034 CS0035 CS0036 CS0037 CS0038 CS0039 CS0040 CS0041 CS0042 CS0043 CS0050 CS0051 CS0052 CS0053 CS0054 CS0055 CS0056 CS0057 CS0058 CS0059 CS0060 {1} Невозможно открыть файл инкрементной сборки{0} для записи Не хватает места на диске или ошибка I/O при записи файл инкрементной сборки {0} Оператор {0} является противоречивым для операндов с типами {1} и {2} Оператор {0} является противоречивым для операнда с типом {1} Параметр out не может иметь атрибут 'In' Невозможно преобразовать null к типу {0}, потому что это тип значения Невозможен доступ к нестатическому члену внешнего типа {0} через вложенный тип {1} Невозможно преобразовать тип {0} к типу {1} Неожиданная ошибка инициализации отладочной информации - {0} Неожиданная ошибка записи отладочной информации в файл {0} - {1} Неожиданная ошибка записи отладочной информации в файл {0} - {1} PDB файл имеет неправильный или устаревший формат. Удалите его и повторите компиляцию Несовместимый доступ: возвращаемый тип {0} менее доступен, чем метод {1} Несовместимый доступ: параметр типа {0} менее доступен, чем метод {1} Несовместимый доступ: поле типа {0} менее доступно, чем поле {1} Несовместимый доступ: свойство типа {0} менее доступно, чем свойство {1} Несовместимый доступ: индекс возвращаемого типа {0} менее доступен, чем индекс {1} Несовместимый доступ: параметр типа {0} менее доступен, чем индекс {1} Несовместимый доступ: возвращаемый тип {0} менее доступен, чем оператор {1} Несовместимый доступ: параметр типа {0} менее доступен, чем оператор {1} Несовместимый доступ: параметр типа {0} менее доступен, чем делегат {1} Несовместимый доступ: параметр типа {0} менее доступен, чем делегат {1} Несовместимый доступ: базовый класс {0} менее доступен, 99 CS0061 CS0065 CS0066 CS0067 CS0068 CS0069 CS0070 CS0071 CS0072 CS0073 CS0074 CS0075 CS0076 CS0077 CS0078 CS0079 CS0100 CS0101 CS0102 CS0103 CS0104 CS0105 CS0106 CS0107 CS0108 CS0109 CS0110 чем класс {1} Несовместимый доступ: базовый интерфейс {0} менее доступен, чем интерфейс {1} {0}: событие должно содержать оба метода add и remove {0}: событие должно быть типа delegate Событие {0} не используется Событие {0} не может быть инициализировано в интерфейсе {0}: событие в интерфейсе не может содержать методы add или remove Событие {0} может располагаться только с левой стороны от операторов += или -= При выполнении события, которое было объявлено в интерфейсе должен быть использован синтаксис свойства {0}: невозможно переопределить; {1} не является событием Методы add и remove в объявлении события должны иметь тело {0}: событие, помеченное как abstract, не может быть инициализировано При использовании отрицательного числа необходимо заключить его в круглые скобки Имя перечислителя 'value__' зарезервировано и не может быть использовано Оператор as должен использоваться с ссылочным типом ({0}это тип значения) Букву {0} легко перепутать с цифрой {1}, для ясности используйте букву {2} Событие {0} может располагаться только с левой стороны от операторов += или -= Параметр с именем {0} уже объявлен В пространстве имен {0} уже содержиться определение для {1} Класс {0} уже содержит определение для {1} Имя {0} не существует в классе или пространстве имен {0} неоднозначная ссылка Директива using для {0} уже использовалась в этом пространстве имен Модификатор {0} невозможно применить для этого элемента Указано более одного модификатора доступа Для члена {0} требуется ключевое слово new, так как он скрывает наследуемый член {1} Член {0} не скрывает наследуемый член. Ключевое слово new не требуется В вычислении константного значения для {0} участвует 100 CS0111 CS0112 CS0113 CS0114 CS0115 CS0116 CS0117 CS0118 CS0119 CS0120 CS0121 CS0122 CS0123 CS0126 CS0127 CS0128 CS0131 CS0132 CS0133 CS0134 CS0135 CS0136 CS0138 CS0139 CS0140 CS0143 CS0144 рекурсивное выражение В классе {0} уже определен член {1} с такими же типами параметра Статический член {0} не может быть помечен как override, virtual или abstract Член {0}, помеченный как override, не может быть помечен как new или virtual Функция {0} скрывает унаследованного члена {1} {0}: нет соответствующего переопределяемого метода Пространство имен непосредственно не содержит членов, таких как поля или методы {0} не содержит определения для {1} {0} означает {1} при ожидаемом {2} {0} означает {1}, что некорректно в данном контексте Для нестатических полей, методов и свойств {0} требуется ссылка на объект Неоднозначный вызов следующих методов или свойств: {0} и {1} {0} недоступен из-за уровня защиты. Метод {0} не соответствует делегату {1} Требуется объект с типом, приводимым к типу {0} Так как функция {0} имеет возвращаемый тип void, то после return не должно быть выражения Локальная переменная {0} уже определена в этой области Левой частью выражения должна быть переменная, свойство или индексатор {0}: статический конструктор должен быть без параметров Переменная {0}, объявленная как const, должна иметь постоянное значение При объявлении вложенного пространства имен нельзя использовать составное имя {0} противоречит объявлению {1} Локальная переменная с именем {0} не может быть объявлена в этой области видимости, так как это даст другой смысл переменной {0}, которая уже объявлена в {1} области видимости Ключевое слово using применяется для объявления пространства имен; {0}-это класс, а не пространсво имен Нет соответствующего цикла, из которого надо выйти по break или continue Метка {0} уже существует Тип {0} не имеет конструктора Невозможно создать экземпляр абстрактного класса или 101 CS0145 CS0146 CS0148 CS0149 CS0150 CS0151 CS0152 CS0153 CS0154 CS0155 CS0156 CS0157 CS0158 CS0159 CS0160 CS0161 CS0162 CS0163 CS0164 CS0165 CS0167 CS0168 CS0169 CS0170 CS0171 CS0172 CS0173 CS0174 CS0175 CS0176 CS0177 интерфейса {0} Значение постоянного поля должно быть задано {0} Рекурсивное определение базового класса между {0} и {1} У делегата {0} нет конструктора Ожидается название метода Ожидается значение константы Ожидается значение перечисляемого типа Метка {0} уже используется в этом выражении Goto case имеет силу только внутри выражения switch Свойство или индексатор {0} не может использоваться в данном контексте из-за ограничения доступа Тип выбрасываемого или перехватываемого объекта должен быть производным от System.Exception Выражение throw без аргументов недопустимо вне блока catch Нельзя передать управление из блока finally Одна и та же метка {0} используется как во внутренней области, так и во внешней Метка {0} не существует в пределах области выражения goto Предыдущий блок catch уже перехватывает все исключения этого или вышестоящего типа {0}: не все ветви кода возвращают значение Обнаружен недоступный код Управление не может быть передано из одной метки case ({0}) в другую Эта метка не используется Использование неинициализированной локальной переменной {0} У делегата {0} нет метода Invoke Переменная {0} объявлена, но нигде не используется Поле {0} нигде не используется Использование неинициализированного поля {0} Поле {0} должно быть инициализировано в конструкторе Тип условного выражения невозможно определить, так как {0} и {1} неявно преобразовываются друг к другу Тип условного выражения невозможно определить, так как не существует преобразования между {0} и {1} Для ссылки необходим базовый класс использование ключевого слова в данном контексте бессмысленно К статическому члену {0} нельзя обращаться через экземпляр; используйте квалификатор типа. Значение параметра {0} должно быть определено в текущем 102 CS0178 CS0179 CS0180 CS0182 CS0183 CS0184 CS0185 CS0186 CS0187 CS0188 CS0191 CS0192 CS0193 CS0196 CS0197 CS0198 CS0200 CS0201 CS0202 CS0204 CS0205 CS0206 CS0208 CS0209 CS0210 методе Неправильная структура инициализации массива {0}, помеченный как extern, не может быть объявлен внутри класса {0} не может быть одновременно extern и abstract Аргументом атрибута должно быть константное выражение, выражение typeof или выражение создания массива Данное выражение всегда имеет предусмотренный ({0}) тип Данное выражение имеет непредусмотренный ({0}) тип {0}-не является ссылочным типом, как требует опереатор lock Использование null невозможно в этом контексте Нет такого оператора {0}, определенного для типа {1} Этот объект не может использоваться пока все поля не инициализированы Присвоить значение полю readonly можно только в конструкторе или при объявлении Поле, отмеченное как readonly, нельзя передавать в качестве out или ref параметра (только в конструкторе) Оператор * или оператор -> должен применяться к указателям Указатель должен быть индексирован только однм значением Присвоить значение статическому полю readonly можно только в статическом конструкторе или при инициализации Статическое поле readonly не может быть предано ка ref или out параметр (только в статическом конструкторе) Нельзя присвоить значение свойству или индексатору {0}возможно только чтение Только операции присваивания, вызова, инкремента, декремента, или объявление нового объекта могут использоваться в качестве предложения Запрос GetEnumerator должен возвращать класс или структуру, а не {0} Предельно допустимое число локальных переменных - 65535 Невозможно вызвать абстрактный метод Свойство или индексатор невозможно использовать в качестве ref или out параметров Невозможно получить адрес или размер переменной управляемого типа ({0}) Локальные переменные, объявленные в выражении fixed должны быть типа указателя Вы должны обеспечить инициализацию в выражении fixed или using 103 CS0211 CS0212 CS0213 CS0214 CS0215 CS0216 CS0217 CS0218 CS0219 CS0220 CS0221 CS0225 CS0227 CS0228 CS0229 CS0230 CS0231 CS0233 CS0234 CS0236 CS0238 CS0239 невозможно получить адрес данного выражения Адрес unfixed выражения можно получить только внутри инициализации выражения fixed Ненужно использовать выражение fixed для получения уже фиксированного адреса Указатели могут использоваться только в контексте unsafe Возвращаемые операторы true и false должны бать типа boоl Чтобы определить оператор {0} необходимо определить соответствущий оператор {1} Для того, чтобы быть применимым в качестве 'коротковычисляемого' оператора, определяемый пользователем оператор {0} должен возвращать результат тогоже типа, что и 2 принимаемых параметра Тип должен содержать объявление оператора true и оператора false переменная {0} объявлена, но ее значение нигде не используется Выход за пределы допустимости во время компиляции блока checked Значение константы не может быть конвертировано к {0} (для переопределения используйте синтаксис {1}) При использовании параметра params необходимо задавать одномерный массив Если в коде содержиться ключевое слово unsafe, то при компиляции должна использоваться опция компилятора /unsafe Тип не содержит определения для {0}, или нет доступа к {0} Неопределенность между {0} и {1} При использовании выражения foreach необходимо передавать как тип, так и идентификатор Параметр params должен быть последним параметром в списке передаваемых параметров Оператор sizeof может использоваться только в блоке unsafe (предполагается использование System.Runtime.InteropServices.Marshal.SizeOf) Тип или пространство имен {0} не существует в классе или пространстве имен {1} (возможно, вы пропустили ссылку на сборку) При инициализации поля нельзя использовать нестатическое поле, метод или свойство {0} Модификатор sealed нельзя применять к {0}, так как он не помечен как override {0}:нельзя наследовать член {1}, так как он помечен как sealed 104 CS0241 CS0242 CS0243 CS0244 CS0245 CS0246 CS0247 CS0248 CS0249 CS0250 CS0251 CS0252 CS0253 CS0254 CS0255 CS0500 CS0501 CS0502 CS0503 CS0504 CS0505 CS0506 CS0507 Параметрические методы не могут иметь значения по умолчанию Операция не определена для пустого указателя Атрибут Conditional непременим к методу {0}, так как этот метод отмечен как override Ключевые слова is и as нельзя использовать для типов указателя Деструкторы и object.Finalize не могут быть вызваны напрямую. Вызывайте IDisposable.Dispose, если он существует Тип или пространство имен с именем {0} не найдено (возможно, вы пропустили директиву using или указатель на сборку) В выражении stackalloc нельзя использовать отрицательное число Размер массива не может быть отрицательным Вместо переопределения object.Finalize. используйте синтаксис деструктора Не надо вызывать базовый класс метода Finalize. Это делается автоматически из деструктора В массиве нельзя использовать отрицательный индекс (индексы в массиве всегда начинаются с 0) Сравнение ссылки; чтобы сравнить значения, необходимо осуществить операцию приведения типов Возможно непреднамеренное сравнение ссылок; для сравнения значений нужно привести правую часть выражения к типу {0} В выражении fixed, справо от знака равенства, нельзя выполнять операцию приведения типов Ключевое слово stackalloc нельзя использовать в блоках catch или finally {0} не может объявляться с телом, так как он отмечен как abstract {0} должен объявляться с телом, так как о не отмечен как abstract или extern Класс {0} не может быть помечен сразу двумя модификаторами: abstract и sealed Абстрактный метод {0} не может быть помечен как virtual Константа {0} не может быть статической {0}: не может быть переопределена; {1}: не является функцией {0}: не может быть переопределен унаследованный член {1}, так как он не отмечен как virtual, abstract, или override {0}: невозможно изменить модификатор доступа при 105 CS0508 CS0509 CS0513 CS0514 CS0515 CS0516 CS0517 CS0518 CS0519 CS0520 CS0522 CS0523 CS0524 CS0525 CS0526 CS0527 CS0528 CS0529 CS0531 CS0533 CS0534 CS0535 CS0536 CS0537 CS0538 CS0539 CS0540 CS0541 переопределении {1} наследуемого метода {2} {0}: невозможно изменить тип возвращаемого значения у замещенного метода {0} {0}: невозможно наследование изолированного класса {1} Неабстрактный класс {1} не может содержать абстрактную функцию {0} {0}: статический конструктор не может явно вызывать конструктор базового класса {0}: модификаторы доступа нельзя использовать в статическом конструкторе Конструктор {0} не может вызывать сам себя {0}: не имеет базового класса и не может вызывать базовый конструктор предписанный тип {0} не определен или не импортирован {0} конфликтует с предписанным пространством имен {0} конфликтует с предписанным типом {0}: структура не может вызывать конструктор базового класса Член структуры {0} типа {1} вызывает зацикливание внутри структуры {0}: в интерфейсе нельзя определять типы Интерфейсы не могут содержать поля Интерфейсы не могут содержать конструкторы {0}: список интерфейсов не может содержать тип {0}: интерфейс уже содержится в списке интерфейсов Наследуемый интерфейс {0} создает циклическую иерархию с {1} {0}: члены интерфейса не могут иметь определение. Методы, объявленные в интерфейсе, реализуются в классе, который унаследует этот интерфейс {0}: скрывает унаследованный абстрактный член {1} {0}: не реализован унаследованный абстрактный члены {1} В классе {0} не реализован унаследованный член {1} В классе {0} не реализован член интерфейса {1}. {2} является статическим, не public или имеет неверный возвращаемый тип Класс System.Object не может иметь базовый класс или реализовывать интерфейс {0} в явном объявлении интерфейса - не интерфейс {0} в явном объявлении интерфейса - не член интерфейса {0}: класс не может реализовать интерфейс {1}, так как интерфейс не наследуется данным классом {0}: явное объявление интерфейса возможно только в классе 106 CS0542 CS0543 CS0544 CS0545 CS0546 CS0547 CS0548 CS0549 CS0550 CS0551 CS0552 CS0553 CS0554 CS0555 CS0556 CS0557 CS0558 CS0559 CS0560 CS0561 CS0562 CS0563 CS0564 CS0567 или в структуре {0}: имена членов типа не должны совпадать с именами самих типов {0}: значение перечислителя находится вне диапазоне данных типа {0}: невозможно переопределить; {1} - не свойство {0}: невозможно переопределить, так как {1} не имеет аксессора get {0}: невозможно переопределить, так как {1} не имеет аксессора set {0}: свойство ли индексатор не могут иметь тип void {0}: свойство или индексатор должны иметь хотя бы один аксессор {0} - новый виртуальный член в изолированном классе {1} Добавленный аксессор {0} не найден в члене интерфейса {1} Явная реализация интерфейса {0} пропускает аксессор {1} {0}: пользователь определил преобразование в/из интерфейса {0}: определенное пользователем преобразование в/из базового класса {0}: определенное пользователем преобразование в/из производного класса Определенный пользователем оператор не может использовать объект незакрытого типа и конвертировать его в незакрытый тип Определенное пользователем преобразование должно конвертировать в/из незакрытого типа Повторяется преобразование в классе {0} Определенный пользователем оператор {0} должен быть объявлен как static и public Параметр и возвращаемый тип операторов ++ и -- должны быть типа, содержащего эти параметры Аксессор {0}: невозможно переопределить {1}, так как {2}скрытый метод {0}: невозможно переопределить {1}, так как это специальный метод компилятора Параметр унарного оператора должен быть типа, содержащего этот оператор Один из параметров бинарного оператора должен быть типа, содержащего этот оператор Первый операнд перегруженного оператора сдвига должен быть типа, содержащего этот оператор, второй операнд должен иметь тип int Интерфейсы не могут содержать операторы 107 CS0568 CS0569 CS0570 CS0571 CS0572 CS0573 CS0574 CS0575 CS0576 CS0577 CS0578 CS0579 CS0580 CS0581 CS0582 CS0583 CS0584 CS0585 CS0586 CS0587 CS0588 CS0589 CS0590 CS0591 CS0592 CS0594 CS0596 CS0597 CS0599 CS0601 CS0602 Структура не может содержать конструктор без параметров {0}: невозможно переопределить {1},так как данная операция не поддерживается языком {0} ссылается на тип, который не поддерживается языком {0}: невозможен явный вызов оператора или аксессора {0}: Нельзя ссылаться на тип через выражение; используйте {1} {0}: в структуре нельзя инициализировать поля Имя деструктора должно совпадать с именем класса Только классы могут содержать деструкторы Пространство имен {0} уже содержит определение для {1} Атрибут Conditional нельзя применять к {0}, потому что это конструктор, деструктор, оператор или явная реализация интерфейса Атрибут Conditional нельзя применять к {0}; это возможно только в том случае, если функция возвращает тип void Повтор атрибута {0} Неправильно заданы аргументы атрибута {0} Указанные аргументы невозможно использовать в атрибуте {0} Атрибут Conditional нельзя применять к членам интерфейса Внутренняя ошибка компилятора. Вероятный виновник - {1}. Пожалуйста, создайте файл сообщения об ошибке с опцией компилятора {1} и предоставьте отчет о вашей проблеме Внутренняя ошибка компилятора: стадия {0}, символ {1} Внутренняя ошибка компилятора: стадия {0} Внутренняя ошибка компилятора: стадия {0} Внутренняя ошибка компилятора: стадия {0} Внутренняя ошибка компилятора: стадия 'LEX' Внутренняя ошибка компилятора: стадия 'PARSE' Определенные пользователем операторы не могут возвращать тип void Недействительное значение аргумента атрибута {0} Атрибут {0} нельзя использовать в объявлении этого типа. Это возможно только в объявлениях {1} Указанная константа вне диапазона типа {0} Атрибут ComImport должен быть указан с атрибутом Guid Атрибут {0} не имеет необходимого числа аргументов {0} - невозможное значение для аргумента атрибута Метод, к которому применяется атрибут DllImport должен быть отмечен как 'static' и 'extern' {0}: эту особенность языка лучше не ипользовать. Используйте {1} 108 CS0609 CS0610 CS0611 CS0612 CS0616 CS0617 CS0618 CS0619 CS0620 CS0621 CS0622 CS0623 CS0625 CS0626 CS0628 CS0629 CS0631 CS0633 CS0634 CS0635 CS0636 CS0637 CS0641 Невозможно применить атрибут к индексатору, помеченному как override Поле или свойство не может быть типа {0} Массив элементов не может быть типа {0} {0}: не является классом атрибута {0}: не является классом атрибута {0} не является корректно названным аргументом атрибута. Аргументом атрибута должны быть поля, которые не определены как readonly, static или const, или нестатические свойства для чтения/записи Член класса {0} устаревший: {1} Член класса {0} устаревший: {1} Индексатор не может быть типа void {0}: виртуальные или абстрактные члены не могут быть закрытыми (private) Выражение инициализации массива можно использовать только при объявлении массивных типов Инициализаторы массивов могут использоваться только при инициализации переменных и полей {0}: когда к структуре явно применяется атрибут StructLayout, ко всем полям этой структуры должен быть применен атрибут FieldOffset Метод, оператор или аксессор {0} отмечен как внешний (external) не имеет атрибутов. Добавьте атрибут DllImport, что бы обеспечить внешнее выполнение {0}: изолированный класс (sealed) не может содержать в себе защищенных членов (protected), так как использование защищенного члена другим классом при наследовании исключено Условный член {0} не может реализовать член интерфейса {1} Индексаторы не могут иметь out или ref параметры Аргументом атрибута IndexerName должен быть индексатор {0}: аргумент верен только для маршаллера типа System.Interop.UnmanagedType.CustomMarshaller {0}: System.Interop.UnmanagedType.CustomMarshaller требует определенное название аргументов ComType и Marshal Атрибут FieldOffset может применяться только к членам, находящимся внутри типов, к которым применяется StructLayout(LayoutKind.Explicit) Атрибут FieldOffset нельзя применять к статическим и постоянным полям {0}: атрибут может применяться только к классам, полученным из System.Attribute 109 CS0642 CS0643 CS0644 CS0645 CS0646 CS0647 CS0648 CS0649 CS0650 CS0652 CS0653 CS0654 CS0655 CS0656 CS0657 CS0658 CS0659 CS0660 CS0661 CS0662 CS0663 CS0664 CS0665 CS0666 CS0667 Возможно ошибочное пустое выражение {0}: аргумент с таким именем уже использовался {0} не может унаследовать особый класс {1} Идентификатор слишком длинный Нельзя применять атрибут DefaultMember к типу, содержащему индексатор Ошибка имитации атрибута {0} - {1} {0}: этот тип не поддерживается языком Значение поля {0} нигде не задано и будет всегда иметь значение по умолчанию {1} Синтаксическая ошибка, неправильное объявление массива. При объявлении спецификатор массива предшествует идентификатору переменной Сравнение с целочисленной константой бесполезно. Константа находится вне диапазона типа {0} Невозможно применить класс атрибута {0}, так как он является абстрактным Невозможен вызов метода {0} без круглых скобок Неправильное расположение атрибута {0}. Все атрибуты в этом блоке будут проигнорированы Отсутствует требуемый компилятором член {0} Неверное местоположение атрибута {0}. Правильное местоположение - {1} Неверное местоположение атрибута {0}. Все атрибуты в этом блоке будут игнорироваться {0} переопределяет Object.Equals(object o), но не переопределяет Object.GetHashCode() {0} определяет оператор == и !=, но не переопределяет Object.Equals(object o) {0} определяет оператор == и !=, но не переопределяет Object.GetHashCode() {0}: нельзя определить только out атрибут у параметра ref. Используйте или оба атрибута сразу (In и Out), или ни одного {0}: методы не могут отличаться только использованием out или ref параметра Константа типа double не может быть преобразована к типу {0}. Используйте суффикс для создания константы данного типа Нельзя использовать оператор = в условном выражении. Попробуйте использовать оператор == {0}: в структуре объявлен защищенный (protected) член Опциональный атрибут методов 'MarshalAs' теперь запрещен. Вместо этого используйте атрибут 'return: переопределение местоположения' с атрибутом 'MarshalAs' 110 CS0668 CS0669 CS0670 CS0672 CS0673 CS0674 CS0675 CS0676 CS0677 CS0678 CS0682 CS0683 CS0684 CS0688 CS0690 CS1001 CS1002 CS1003 CS1004 CS1005 CS1007 CS1008 CS1009 CS1010 CS1011 Два индексатора имеют одинаковые имена; атрибут IndexerName должен использоваться с одним и тем же именем в пределах одного типа Класс с атрибутом ComImport не может иметь определенный пользователем конструктор Поле не может быть типа void Член {0} - переопределенный устаревший член {1}. Примените атрибут Obsolete к {0} System.Void не может быть использован в С#. Чтобы получить объект типа void используйте typeof(void) Вместо {0} используйте ключевое слово {1} Использование побитового or для расширенного знакового операнда; рассмотрите возможность первоначального приведения к меньшему беззнаковому типу Нельзя передавать переменную, помеченную ключевым словом volatile {0} в качестве out или ref параметра Переменная, объявленная с помощью ключевого слова volatile {0} не может быть типа {1} Поле {0} не может быть объявлено одновременно как volatile и readonly {0} не может реализовать {1}, потому что это не поддерживается языком Явно реализованный метод {0} не может реализовать {1}, потому что это аксессор Если к интерфейсу {0} применяется {1}, то необходимо применить и {2} {0}(метод, аксессор свойства или аксессор события) имеет требование соединения, но при этом переопределяет или реализует {1}(метод, аксессор свойства или аксессор события), который не имеет требования соединения. Возможно возникновение проблемы безопасности Входной файл {0} не является корректным PE-файлом, потому что содержит искаженные метаданные Ожидается идентификатор Ожидается ; Синтаксическая ошибка, ожидается {0} Повтор модификатора {0} Косвенное управление типом невозможно Свойство аксессора уже определено Ожидается тип byte, sbyte, short, ushort, int, uint, long, или ulong Неизвестная последовательность символов Разделитель в константе Пустая символьная константа 111 CS1012 CS1013 CS1014 CS1015 CS1016 CS1017 CS1018 CS1019 CS1020 CS1021 CS1022 CS1023 CS1024 CS1025 CS1026 CS1027 CS1028 CS1029 CS1030 CS1031 CS1032 CS1033 CS1034 CS1035 CS1036 CS1037 CS1038 CS1039 CS1040 CS1041 CS1043 CS1044 CS1055 CS1501 CS1502 Слишком много символов в символьной константе Невозможное число Ожидается get или set аксессор Отсутствует объект, строка или тип класса Ожидается название аргумента атрибута Выражение try уже имеет блок catch Ожидается ключевое слово this или base Ожидается перегружаемый унарный оператор Ожидается перегружаемый бинарный оператор Слишком большая целая константа Ожидается определение типа или пространства имен, или 'конец файла' Внедренное выражение не может быть декларацией или оператором с меткой Ожидается директива препроцессора Ожидается однострочный комментарий или признак конца строки Ожидается ) Ожидается директива #endif Неожиданная директива препроцессора #error: {0} #warning: {0} Ожидается тип Директивы препроцессора #define/#undefine должны использоваться в начале программы Превышен предел компилятора: файл не может содержать более {0} линий Превышен предел компилятора: строка не может содержать более {0} знаков Найден конец файла, ожидается {0} Ожидается ( или . Ожидается перегруженный оператор Ожидается директива #endregion Незаконченная строка Директивы препрцессора должны находиться в начале строки Ожидается идентификатор, а не ключевое слово {0} Ожидается { или ; Нельзя использовать больше одного типа в выражениях for, using, fixed или при объявлении Ожидается аксессор add или remove Нет перегруженного метода {0}, имеющего {1} параметров Перегруженный метод соответствует {0}, но имеет некорректные аргументы 112 CS1503 CS1504 CS1507 CS1508 CS1509 CS1510 CS1511 CS1512 CS1513 CS1514 CS1515 CS1517 CS1518 CS1519 CS1520 CS1521 CS1522 CS1523 CS1524 CS1525 CS1526 CS1527 CS1528 CS1529 CS1530 CS1533 CS1534 CS1535 Аргумент {0}: невозможно преобразовать тип {1} к типу {2} Невозможно открыть исходный файл {0} ({1}) Невозможно ссылаться на ресурсный файл, когда идет построение модуля Идентификатор ресурса {0} уже использовался в этой сборке Упомянутый файл {0} не является сборкой. В качестве out или ref параметра должна использоваться переменная, а не число Ключевое слово base бесполезно использовать в статическом методе Ключевое слово base бесполезно использовать в данном контексте Ожидается } Ожидается { Ожидается {0} Недействительное выражение препроцессора Внутри пространства имен можно объявлять классы, делегаты, перечисления, интерфейсы, структуры и пространства имен Недействительный символ {0} в объявлении класса, структуры или члена интерфейса Класс, структура или метод интерфейса должен иметь возвращаемый тип Недопустимый базовый тип Пустой блок switch В блоке switch коду должно предшествовать ключевое слово case или default Ожидается блок catch или finally Недействительный термин {0} в выражении Оператор new требует после типа () или [] Элементы пространства имен не могут быть объявлены как private, protected, или protected internal Ожидается ; или = (нельзя задавать аргументы конструктора в объявлении) Предложение using должно предшествовать всем другим элементам пространства имен Ключевое слово new нельзя применять к элементам пространства имен Метод Invoke для делегата не может быть вызван непосредственно Метод перегруженного бинарного оператора {0} может принимать только два параметра Метод перегруженного унарного оператора {0} может 113 CS1536 CS1537 CS1540 CS1541 CS1542 CS1545 CS1546 CS1547 CS1548 CS1549 CS1551 CS1552 CS1553 CS1554 CS1555 CS1556 CS1557 CS1558 CS1559 CS1560 CS1562 CS1563 CS1565 CS1566 CS1567 CS1569 CS1570 принимать только один параметр Недействительный параметр типа void Using {0} уже объявлено в этом пространстве имен Невозможен доступ к защищенному члену {0} посредством спецификатора типа {1}; спецификатор должен быть типа {2} Некорректное подключение опции: {0} - не может подключить директории {0} является сборкой и не может быть добавлена в сборку; используйте опцию '\R' Свойство, индексатор или событие {0} не поддерживается языком; попытайтесь вызвать непосредственно методы 'set accessor' или 'get accessor' Свойство, индексатор или событие {0} не поддерживается языком; попытайтесь вызвать непосредственно метод {1} Ключевое слово {0} не может быть использовано в данном контексте Криптографическая ошибка при подписывании сборки {0} {1} Не найдена соответствующая криптографическая служба Индексатор должен иметь, по крайней мере, один параметр Спецификатор типа аrray, [], должен находиться перед именем параметра Объявление недействительно; используйте {0} Объявление недействительно; используйте {0} Не найден {0} для метода Main в программе {1} {0}, указанный для метода Main должен являться действительным классом или структурой {0}, указанный в методе Main, не найденный в программе {0}, был найден в {1} {0} не имеет соответствующего метода Main {0} импортирован и не может использоваться как точка входа в прогрмму {1} Имя файла, указанное с директивой #line, слишком длинное Для выходных данных без исходного кода должна быть указана опция \out Выходной файл {0} не имеет исходного кода Конфликтуют выбранные опции компилятора: /win32res и /win32ico Ошибка чтения файла ресурса {0} - {1} Ошибка генерации ресурса Win32: {0} Ошибка генерации файла XML документации {0} ({1}) XML комментарии в {0} имеет неправильный XML формат 114 CS1571 CS1572 CS1573 CS1574 CS1575 CS1576 CS1577 CS1578 CS1579 CS1580 CS1581 CS1583 CS1584 CS1585 CS1586 CS1587 CS1588 CS1589 CS1590 CS1591 CS1592 CS1593 CS1594 CS1595 {1} XML комментарии имеет дубликат тэга param для {0} XML комментарии имеет тэг param для {0}, но параметра с таким именем нет Параметр {0} не имеет соответствующего тэга param в XML комментарии (другие параметры имеют) XML комментарий имеет атрибут cref {0},но такой атрибут не найден В выражении stackalloc должны использоваться квадратные скобки ([]) Номер линии, указанный в директиве #line, отсутствует или недействителен Ошибочная генерация сборки - {0} Ожидается имя файла, однострочный комментарий или конец строки Выражение foreach не может работать с переменными типа {0}, так как {1} не содержит определение для {2} В атрибуте cref XML комментария неправильно указан тип для параметра {0} В атрибуте cref XML комментария указан неправильный возвращаемый тип Файл {0} не является корректным ресурсным файлом Win32 XML комментарий на {0} имеет синтаксически некорректный атрибут cref {1} Модификатор члена {0} должен указываться перед типом члена и его именем При создании массива необходимо его инициализировать или указать размер массива XML комментарий указан для элемента языка, который не подлежит XML комментированию Невозможно определить директорию общеязыковой среды выполнения (CLR) - {0} Невозможно включить XML фрагмент {0} в файл {1} - {2} Некорректный XML элемент include - пропущен атрибут file Отсутствует XML комментарий к типу или члену {0} Некорректно составленный XML в комментариях, подключающих файл - {0} Указанное число аргументов ({1}) при обращении к делегату {0} не совпадает с числом аргументов, объявленным при декларации делегата Некоторые аргументы делегаты {0} - недействительны {0} определен в нескольких местах; используйте определение из {1} 115 CS1596 CS1597 CS1598 CS1599 CS1600 CS1601 CS1602 CS1603 CS1604 CS1605 CS1606 CS1607 CS1608 CS1609 CS1610 CS1611 CS1612 CS1613 CS1614 CS1618 CS1619 CS1900 CS1901 CS1902 CS1904 XML документация не обновилась в процессе пошагового построения; используйте ключ /incremental, чтобы обновить XML документацию Точка с запятой после метода или блока аксессора недействительна XML анализатор не может быть загружен по следующей причине: {0}. Файл XML документации {1} не будет сгенерирован Метод или делегат не может возвращать тип {0} Компиляция отменена пользователем Параметр метода или делегата не может быть типа {0} {0} уже определен в этой сборке Пошаговое построение требует целевое имя, указанное с помощью \out Невозможно переопределить {0}, так как переменная определена только для чтения Невозможно передать {0} как out или ref параметр, так как переменная определена только для чтения Подписывание сборки не удалось; выход может быть не подписан - {0} Генерация сборки - {0} Атрибут RequiredAttribute нельзя применять к типам, определенным в С# Нельзя указывать модификаторы при объявлении аксессоров Невозможно удалить временный файл {0}, служащий ресурсом Win32 по умолчанию - {1} Параметр params не может быть объявлен как ref или out Невозможно изменить возвращаемое значение {0}, потому что оно не является переменным Управляемый класс-обертка {0} кокласса для интерфейса {1} неверен или не может быть найден (возможно, не указана ссылка на сборку) Неоднозначно задан атрибут {0}; используйте '1' или '2' Невозможно создать делегат с {0} Невозможно создать временный файл {0} - {1} Значение уровня предупреждений должно быть в диапазоне от 0 до 4 Указаны конфликтующие опции компилятора: предупреждение нулевого уровня. Рассматривайте предупреждение как ошибку Неправильная опция {0} для /debug; должно быть либо full, либо pdbonly {0} - невозможный номер предупреждения 116 CS2000 CS2001 CS2002 CS2003 CS2005 CS2006 CS2007 CS2008 CS2011 CS2012 CS2013 CS2014 CS2015 CS2016 CS2017 CS2018 CS2019 CS2020 CS2021 CS2022 CS2023 CS2024 CS3001 CS3002 CS3003 CS3004 CS3005 CS3006 CS3008 CS3009 CS3010 Неожиданная ошибка инициализации компилятора Исходный файл {0} не найден Исходный файл {0} определен многократно Файл ответа {0} включен многократно Отсутствует спецификация для опции командной строки {0} Синтаксическая ошибка командной строки: отсутствует {0} для включения {1} Неизвестная опция командной строки: {0} Не указаны входы Невозможно открыть файл ответа {0} Не открывается файл для записи {0} Неверное значение {0} для базы образа Опция компилятора {0} устарела, вместо нее используйте {0} {0} - бинарный файл. Компилятор ожидает файл исходного кода Кодовая страница некорректна или не инсталлирована Невозможно определить \main при создании модуля или библиотеки Невозможно найти файл сообщений 'cscmsgs.dll' Неправильный целевой тип для \target: должно быть 'exe', 'winexe', 'library', или 'module' Только первый набор файлов может компилироваться в целевой модуль, отличный от {0} Имя файла {0} слишком длинное или недопустимое Опции '/out' и '/target' должны располагаться перед именами исходных файлов Опция /noconfig игнорируется, так как она была определена в файле ответа {0} - недопустимый номер выравнивания раздела файла Аргумент типа {0} CLS-несовместим Возвращаемый тип метода {0} CLS-несовместим Тип переменной {0} CLS-несовместим Разбиение и смешивание символов уникода CLSнесовместимо Идентификатор {0} отличается от уже объявленного идентификатора только регистром. Это CLS-несовместимо Перегружаемый метод {0} отличается только спецификаторами out или ref . Это CLS-несовместимо Идентификатор {0} CLS-несовместим {0}: базовый тип {1} CLS-несовместим {0}: CLS-совместимые интерфейсы должны содержать CLSсовместимые методы 117 CS3011 CS3012 CS3013 CS3014 CS3015 CS3016 CS5000 CS5001 {0}: только CLS-совместимые члены могут быть абстрактными В сборке необходимо задавать CLS-совместимые атрибуты Добавленный модуль CLS-несовместим, или пропущен атрибут CLSCompliant {0} не может быть помечен как CLSCompliant, так как сборка не помечена как CLSCompliant {0} не имеет доступных конструкторов, которые используют только CLS-совместимые типы Массивы или аргументы атрибутов CLS-несовместимы {0} - неизвестная опция компилятора Программа {0} не имеет определенной точки входа (отсутствует метод main) 118 Глоссарий PositiveInfinity – константа. Значение этой константы — результат деления положительного числа нулем. Эта константа возвращается, когда результат операции больше чем MaxValue. NegativeInfinity – константа. Значение этой константы — результат деления отрицательного числа нулем. Эта константа возвращается, когда результат операции — меньше чем MinValue. NaN-константа. Значение этой константы — результат деления нуля на нуль. Эта константа возвращается, когда результат операции неопределен. 119 Литература 1. Чарльз Петцольд, Программирование для Microsoft Windows на C#. Том1,2. М.: Издательский отдел “Русская Редакция”,2002. 2. Эндрю Троелсен, С# и платформа .NET. Библиотека программиста. СПб.: Питер, 2002. 120 Содержание 1. Элементы языка .............................................................................................. 3 1.1 Комментарии ................................................................................................ 3 1.2 Идентификаторы ........................................................................................ 4 1.3 Ключевые слова........................................................................................... 5 1.4 Константы ....................................................................................................... 5 1.4.1 Целые знаковые .................................................................................... 5 1.4.2 Целые беззнаковые ............................................................................. 5 1.4.3 С плавающей точкой .......................................................................... 6 1.4.4 Символьные............................................................................................. 6 1.4.5 Строковые ................................................................................................ 7 1.5 Выражения ..................................................................................................... 7 1.6 Операции......................................................................................................... 7 1.6.1 Арифметические операции .............................................................. 8 1.6.2 Логические операции ......................................................................... 8 1.6.3 Операции отношения ......................................................................... 8 1.6.4 Операции присваивания ................................................................... 8 1.6.5 Операции инкремента и декремента .......................................... 9 1.6.6 Операции с массивами....................................................................... 9 1.6.7 Операции класса ................................................................................ 10 1.6.8 Побитовые операции ........................................................................ 10 1.6.9 Прочие операции ................................................................................ 10 1.6.10 Операции распределения памяти .............................................. 11 1.6.11 Приоритет и порядок выполнения операций ....................... 11 1.6.12 Арифметические преобразования.............................................. 12 1.7 Операторы .................................................................................................... 12 1.7.1 Оператор выражения ....................................................................... 12 1.7.2 Оператор метки ................................................................................... 12 1.7.3 Пустой оператор ................................................................................. 12 1.7.4 Составной оператор .......................................................................... 12 1.7.5 Управляющие конструкции ........................................................... 13 1.7.5.1 if..else ................................................................................................. 13 1.7.5.2 for ......................................................................................................... 13 1.7.5.3 while .................................................................................................... 14 1.7.5.4 goto ...................................................................................................... 14 1.7.5.5 switch .................................................................................................. 15 1.7.5.6 do .......................................................................................................... 15 1.7.5.7 foreach ................................................................................................ 16 1.7.5.8 return .................................................................................................. 17 1.7.5.9 break ................................................................................................... 17 1.7.5.10 continue ........................................................................................... 18 121 2. Способы структурирования программы ............................................. 19 2.1 Логическая организация программы ............................................... 19 2.2 Физическая организация программы .............................................. 19 2.3 Объявления .................................................................................................. 20 2.3.1 Управление памятью......................................................................... 20 2.3.2 Типы данных ......................................................................................... 21 2.3.2.1 Структурные типы ........................................................................ 21 2.3.2.2 Ссылочные типы ........................................................................... 25 2.4 Классы ............................................................................................................ 27 2.4.1 Объявление ........................................................................................... 27 2.4.2 Члены класса........................................................................................ 29 2.4.2.1 Поля .................................................................................................... 29 2.4.2.2 Методы ............................................................................................... 32 2.4.2.3 Cвойства ............................................................................................ 35 2.4.2.4 Индексаторы ................................................................................... 37 2.4.2.5 Конструкторы.................................................................................. 39 2.4.2.6 Деструкторы .................................................................................... 40 2.4.3 Инкапсуляция....................................................................................... 41 2.4.4 Наследование ....................................................................................... 41 2.4.5 Полиморфизм ....................................................................................... 43 2.5 Структуры ..................................................................................................... 44 2.5.1 Объявление ........................................................................................... 44 2.5.2 Члены структуры ................................................................................ 45 2.5.3 Различия структур и классов........................................................ 45 2.6 Массивы ......................................................................................................... 47 2.6.1 Типы массива ....................................................................................... 47 2.6.2 Объявление массива ......................................................................... 47 2.6.3 Члены массива ..................................................................................... 48 2.7 Интерфейсы ................................................................................................. 48 2.7.1 Объявление ........................................................................................... 48 2.7.2 Члены интерфейса............................................................................. 49 2.7.3 Реализация интерфейса .................................................................. 50 2.7.4 Наследование ....................................................................................... 50 2.8 Перегрузка операций .............................................................................. 52 2.8.1 Унарные операции ............................................................................. 52 2.8.2 Бинарные операции .......................................................................... 52 2.9 Делегаты........................................................................................................ 54 2.9.1 Объявление ........................................................................................... 54 2.9.2 Одиночные делегаты ........................................................................ 55 2.9.3 Комбинированные делегаты ......................................................... 55 2.9.4 Использование делегатов .............................................................. 57 2.10 События.......................................................................................................... 58 122 2.10.1 Объявление ........................................................................................... 58 2.10.2 Генерация событий............................................................................ 58 2.11 Атрибуты........................................................................................................ 59 2.11.1 Типы данных допустимые в атрибутах .................................... 59 2.11.2 Объявление ........................................................................................... 60 2.11.3 Конструктор .......................................................................................... 60 2.11.4 Свойства ................................................................................................. 61 2.11.5 Применение атрибутов .................................................................... 61 2.11.5.1Применение атрибутов на уровне классов и методов... .............................................................................................................. 61 2.11.5.2Применение атрибутов на уровне сборок ....................... 62 2.11.5.3Применение атрибутов на уровне модулей .................... 63 2.11.6 Специализированные атрибуты .................................................. 63 2.11.7 Определение собственного атрибута ....................................... 65 2.11.8 Использование атрибута AttributeUsageAttribute ............... 66 2.11.9 Доступ к информации, хранящейся в атрибутах ................ 67 2.11.9.1Получение одиночного атрибута ......................................... 67 2.11.9.2Получение списка однотипных атрибутов ...................... 68 2.11.9.3Получение списка разнотипных атрибутов .................... 69 2.12 Исключения.................................................................................................. 70 2.12.1 Генерация и перехват исключения ........................................... 71 2.13 Директивы препроцессора ................................................................... 73 3. Встроенные элементы ................................................................................ 76 3.1 Класс System.Math.................................................................................... 76 3.1.1 Методы..................................................................................................... 76 3.1.2 Поля .......................................................................................................... 86 3.2 Класс System.Random ............................................................................. 87 3.2.1 Методы..................................................................................................... 87 3.3 Структура DateTime ................................................................................. 90 3.3.1 Методы..................................................................................................... 90 3.3.2 Свойства ................................................................................................. 91 3.4 Структура TimeSpan................................................................................. 95 3.4.1 Свойства ................................................................................................. 95 4. Сообщения об ошибках компиляции .................................................. 98 123 Минеев С.А., Пряничников А.В., Кузьмина И.В. Язык программирования С# _______________________________________________________ Подписано к печати . Формат 60х84 116 . Бумага писчая. Печать офсетная. Усл. печ. л. 1.5 Заказ . Тираж 200 экз. ________________________________________________________ Нижегородский государственный университет им. Н.И.Лобачевского 603600 ГСП-20, Н. Новгород, просп. Гагарина, 23. ________________________________________________________ Типография ННГУ. 603000, Н. Новгород, ул. Б. Покровская, 37.