Особенности языка C# 5.0 .NET FRAMEWORK 4.5
Покупка
Основная коллекция
Тематика:
Программирование на C и C++
Издательство:
НИЦ ИНФРА-М
Авторы:
Костиков Юрий Александрович, Мокряков Алексей Викторович, Павлов Виталий Юрьевич, Романенков Александр Михайлович
Год издания: 2015
Кол-во страниц: 38
Дополнительно
Вид издания:
Учебно-методическая литература
Уровень образования:
ВО - Бакалавриат
ISBN-онлайн: 978-5-16-103256-5
Артикул: 384200.01.99
Тематика:
ББК:
УДК:
ОКСО:
- ВО - Бакалавриат
- 09.03.01: Информатика и вычислительная техника
- 09.03.02: Информационные системы и технологии
- 09.03.03: Прикладная информатика
ГРНТИ:
Скопировать запись
Фрагмент текстового слоя документа размещен для индексирующих роботов
ОСОБЕННОСТИ ЯЗЫКА C# 5.0 .NET FRAMEWORK 4.5 Методическое пособие для студентов Костиков Ю. А., Мокряков А. В., Павлов В. Ю., Романенков А. М. МОСКВА
Содержание. Кортежи. 2 Основные потоки приложения. 3 Некоторые оптимизации GC. 4 Класс System.IO.Path. 6 Исключения. 7 События. 11 Элементы Window Forms. 13 Упражнения 21 ADO.NET. Подключаемый уровень 23 ADO.NET. Автономный уровень 29
Кортежи. Допустим, мы хотим написать функцию, которая возвращает небольшой набор некоторых значений разного типа. Возникает вопрос - как возвращать эти данные? Так, проблему можно решить несколькими способами: 1) сделать возвращаемым значением функции object или object[]. 2) Использовать анонимные типы и dynamic. 3) Использовать ref/out параметры. 3) Объявить и использовать свою структуру данных. Недостаток первого подхода заключается в том, что здесь будет происходить процесс упаковки/распаковки объектов, что снижает типобезопасность, читабельность и производительность программы. Динамическая типизация повышает неявность кода. И вообще её следует избегать при любой возможности. ref/out параметры накладывают ограничения на код, так же теряется логическая связь значений. Использование собственной структуры данных кажется оптимальным вариантом. Но давайте предположим, что наша функция - лишь малая часть какого либо проекта. И у нас не одна, а множество подобных вспомогательных функций. Объявление "второстепенных" типов данных снижает читабельность кода и занимает немало времени. Для решение данной проблемы в язык C# ввели кортежи(Tuple) - шаблонные классы, которые комбинируют значения разных типов. Существует 8(по количеству типов-параметров) шаблонных классов Tuple, а так же статический класс Tuple, содержащий метод Create, который облегчает создание кортежей. Пример: static Tuple<bool, int, string> Foo() { //... // две эквивалентных строчки. //return new Tuple<bool, int, string>(true, 20, "Alex");
return Tuple.Create(true, 20, "Alex"); } { //... var val = Foo(); if (val.Item1) Console.WriteLine("{0} - {1}", val.Item2, val.Item3); } ItemX - свойство только для чтения. Важно, что все элементы кортежа являются статически типизированными. Кортеж является ссылочным типом. Однако, метод Equals экземпляра типа перегружен так, что сравнивает значения полей. Так же кортеж удобно использовать для передачи нескольких значений методу в составе одного параметра. Основные потоки приложения. Если вы запустите простое консольное приложение, то с помощью монитора ресурсов Windows можно обнаружить, что в программе запущен вовсе не один поток, а несколько больше. В чём же дело ? При запуске любого .NET приложения запускаются следующие потоки: 1) Главный поток 2) Поток(-и) сборщика мусора (GC) 3) Поток финализации* 4) Поток, отслеживающий системные события. В действительности, потоков может быть больше, особенно в Debug-сборке. Под системными событиями подразумеваются изменения настроек и параметров дисплея, изменение системной коллекции шрифтов, завершение работы системы, изменение системных параметров, остановка и возобновление работы системы. Данные события определены в классе Microsoft.Win32.SystemEvent. * Если у объекта реализован метод Finalize(), то он при сборке мусора помещается в отдельную очередь объектов, ожидающих вызова Finalize, которая обрабатывается в отдельном высокоприоритетном потоке.
Некоторые оптимизации GC. 1. Использование нескольких процессоров Эта оптимизация предполагает, что на многопроцессорной машине собирать мусор можно, используя сразу несколько процессоров. Чем больше процессоров, тем больше скорость сборки мусора. Однако если куча одна, то доступ к ее структуре придется синхронизировать. А это может свести на нет все преимущества распараллеливания. Чтобы этого избежать, можно завести по отдельной куче на каждый процессор. Для этого нужно подправить конфигурационный файл приложения. <runtime> <gcServer enabled="true"/> </runtime> По умолчанию данное свойство выставлено в false. Это можно проверить, вызвав свойство System.Runtime.GCSettings.IsServerGC Данная оптимизация увеличивает количество потоков приложения примерно на число процессоров(ядер). 2. Параллельная сборка мусора. По умолчанию, поток(-и) GC в фоновом режиме ведёт(-ут) процесс построения графа объектов без приостановки управляемых потоков. Поскольку в любой момент управляемые потоки могут изменить граф и пересечься с GC потоком, требуется синхронизация со всеми операциями, модифицирующими управляемые ссылки, что несколько замедляет производительность. Однако во многих случаях такое замедление незаметно. Зато это позволяет избавиться от паузы, вызванной построением графа объектов. А малый размер пауз очень важен в интерактивных приложениях. Несмотря на всё данную оптимизацию можно отключить <runtime>
<gcConcurrent enabled="false"/> </runtime> 3. Изменение режима задержки для сборки мусора (LatencyMode). Задержка - время, в течение которого сборщик мусора вмешивается в работу приложения. Чтобы освободить объекты, сборщик мусора должен остановить все выполняющиеся потоки приложения. В некоторых ситуациях, например, при получении приложением данных или при отображении содержимого, полная сборка мусора может произойти в критическое время и привести к снижению производительности. Можно настроить уровень вмешательства сборщика мусора путем задания для свойства System.Runtime.GCSettings.LatencyMode одного из значений System.Runtime.GCLatencyMode: Bath Отключает параллельную сборку мусора. Рекомендован для приложений без графического интерфейса. Отключает параллельную сборку мусора переопределяет параметр конфигурации среды выполнения <gcConcurrent> . Interactive Включает параллельную сборку мусора. Самый сбалансированный режим LowLatency Сборщик мусора работает только с поколениями 0 и 1. Это режим наименьшего вмешательства. Данный режим нужно включать только при критических операциях. SustainedLowLatency Сборщик мусора анализирует поколения 0 и 1, и фоновый(параллельный) сбор поколения 2. Не может использоваться, если отключена параллельная сборка мусора. Этот режим приводит к увеличению размера управляемой кучи больше, чем
другие режимы. Так же он не сжимает управляемую кучу, что увеличивает фрагментацию. В Low-режимах полная сборка мусора происходит только в том случае, если система испытывает недостаток памяти. После завершения критических операций с Low-режимом нужно вернуться к режиму с более высокой задержкой. Это позволит GC освободить память (в основном за счёт поколения 2) и оптимизировать структуру управляемой кучи. Класс System.IO.Path. Данный класс позволяет кроссплатформенно работать с путями в файловой системе - помогает формировать корректные и определять ошибочные пути. Упрощает основные операции с путями. Элементы класса не работают с файловой системой, они лишь позволяют определить корректен ли формат пути. Для примера рассмотрим несколько строк. Избранные свойства и функции класса: char DirectorySeparatorChar возвращает символ, разделяющий уровни дирректорий. char PathSeparator возвращает символ разделяющий пути в переменной окружения PATH. string Path.Combine (params string[] paths) объединяет строки-параметры в путь. char[] Path.GetInvalidFileNameChars возвращает символы, которые не разрешены в именах файлов. char[] Path.GetInvalidPathChars возвращает символы, запрёщенные в именах путей. string Path.GetPathRoot возвращает корневой каталог для заданного пути. Примеры использования: string s = Path.Combine(@"C:\", "MyDocuments", "Images"); // получим "C:\MyDocuments\Images"
Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "hello")); // ... // можем проверить пользовательский ввод на корректность bool isError = s.Any(ch => Path.GetInvalidFileNameChars().Contains(ch)); Path.GetExtension(@"U:\doc1.txt"); // получим ".txt" s = @"U:\doc1"; if (!Path.HasExtension(s)) s = Path.ChangeExtension(s, "txt"); // получим @"U:\doc1.txt"; // причём вызов Path.ChangeExtension(s, ".txt") вернёт аналогичную строку. Исключения. Часть I. Рассмотрим пример - есть некоторая функция с объявленными блоками try catch-finally (блок catch необязателен) : static int Test() { try { return SomeNumber(); } finally { Foo(); } } Как известно, блок finally исполняется всегда. Поэтому, если компилятор встречает оператор return, то возвращаемое значение кэшируется, затем выполняется код блока finally, и только после этого идёт возврат из функции. Выше написанный код при компиляции развернётся примерно так : static int Test()
{ int CS$1$0000; try { CS$1$0000 = SomeNumber(); } finally { Foo(); } return CS$1$0000; } Примерно так выглядит IL-код. .method private hidebysig static int32 Test() cil managed { .maxstack 1 .locals init ( [0] int32 CS$1$0000) L_0000: call int32 Program::SomeNumber() L_0005: stloc.0 L_0006: leave.s L_000e L_0008: call void Program::Foo() L_000d: endfinally L_000e: ldloc.0 L_000f: ret .try L_0000 to L_0008 finally handler L_0008 to L_000e } Поэтому будьте внимательны в написании кода, если возвращаемым значением является некоторый ресурс, который освобождается в блоке finally. В таком случае, вы, скорее всего, ошиблись с архитектурой.
Следующая конструкция не верна, т.к. оператор throw без параметров может быть только внутри блока catch. try { //... } finally { throw; // ! } И следующий код тоже ошибочен (правда это другой номер ошибки). Хоть теперь вызов throw, в отличие от пред. примера находится внутри блока catch. Дело в том, что внутренний finally ничего не знает о внешнем исключении (и очевидно, внутренний finally относится только к внутр. try) try { } catch { try { } finally { throw; } } Также стоит отметить, что в блоке finally запрещён возврат значения из функции.