- •Учебное пособие по дисциплине «программирование»
- •Оглавление
- •1 С# 6.0 и платформа .Net 4.6 6
- •С# 6.0 и платформа .Net 4.6
- •Платформа Microsoft .Net Framework.
- •Понятия приложения, проекта, решения
- •Среда разработки Visual Studio .Net
- •Создание первого проекта
- •Компиляция и выполнение программы в среде clr
- •Технология объектно-ориентированного программирования
- •Состав языка
- •Типы данных
- •Переменные и константы
- •Организация ввода-вывода данных. Форматирование.
- •Вывод данных
- •Ввод данных
- •Операции
- •3. Отрицание:
- •9. Условная операция.
- •Выражения и преобразование типов
- •Операторы языка c#
- •Операторы следования
- •Операторы ветвления
- •Оператор выбора switch
- •Операторы цикла
- •Операторы безусловного перехода
- •Методы: основные понятия
- •Необязательные параметры
- •Именованные параметры
- •Перегрузка методов
- •Рекурсивные методы
- •Обработка исключений
- •Оператор try
- •Операторы checked и unchecked
- •Генерация собственных исключений
- •Полезные совет
- •Массивы
- •Одномерные массивы
- •Многомерные массивы
- •Ступенчатые массивы
- •Оператор foreach и его использование при работе с массивами
- •Символы и строки
- •Символы char
- •Неизменяемые строки string
- •Изменяемые строки
- •Регулярные выражения
- •Метасимволы в регулярных выражениях
- •Поиск в тексте по шаблону
- •Редактирование текста
- •Организация с#-системы ввода-вывода
- •Байтовый поток
- •Символьный поток
- •Двоичные потоки
- •Перенаправление стандартных потоков
- •Работа с файловой системой
- •Работа с каталогами Абстрактный класс FileSystemInfo
- •Класс DirectoryInfo
- •Класс Directory
- •Работа с файлами Класс Filelnfo
- •Класс File
- •Основные понятия
- •Данные: поля и константы
- •Конструкторы
- •Конструкторы экземпляра
- •Конструкторы класса
- •Свойства
- •«Один класс – один файл»,
- •Классы (продолжение)
- •Деструкторы
- •Индексаторы
- •Операции класса
- •Унарные операции
- •Бинарные операции
- •Операции преобразования типов
- •Иерархия классов
- •Наследование
- •Использование защищенного доступа
- •Наследование конструкторов
- •1) Позволяет вызвать конструктор базового класса:
- •2) Позволяет получить доступ к члену базового класса, который скрыт "за" членом производного класса.
- •Многоуровневая иерархия
- •Переменные базового класса и производного класса
- •Виртуальные методы
- •Абстрактные методы и классы
- •Запрет наследования
- •Обобщенные типы
- •Значения по умолчанию
- •Статические поля обобщенных классов
- •Ограничения универсальных типов
- •Использование нескольких универсальных параметров
- •Обобщенные методы
- •Наследование обобщенных типов
- •Анонимные типы
- •Методы расширения
- •Интерфейсы
- •Введение в интерфейсы
- •Интерфейсы в преобразованиях типов
- •Обобщенные интерфейсы
- •Явное применение интерфейсов
- •Клонирование объектов. Интерфейс iCloneable
- •Сортировка объектов. Интерфейс iComparable
- •Применение компаратора
- •Ковариантность и контравариантность обобщенных интерфейсов
- •Структуры
- •Перечисления enum
- •Коллекции
- •Введение в коллекции
- •Необобщенные коллекции
- •Обобщенные коллекции
- •Инициализация словарей
- •Класс ObservableCollection
- •Индексаторы и создание коллекций
- •Интерфейсы iEnumerable и iEnumerator
- •Итераторы и оператор yield
- •Именованный итератор
- •Класс Hashtable
- •Делегаты, события и лямбды
- •Делегаты
- •События
- •Класс данных события AccountEventArgs
- •Анонимные методы
- •Ковариантность и контравариантность делегатов
- •Ковариантность и контравариантность в обобщенных делегатах
- •Делегаты Action, Predicate и Func
- •Встроенные Методы (Expression–Bodied)
- •Сериализация
- •Введение в сериализацию объектов
- •Атрибут Serializable
- •Формат сериализации
- •Бинарная сериализация. BinaryFormatter
- •Сериализация в формат soap. SoapFormatter
- •Сериализация в xml. XmlSerializer
- •Сериализация в json. DataContractJsonSerializer
- •Сборка мусора, управление памятью и указатели
- •Сборщик мусора в c#
- •Класс System.Gc
- •Финализируемые объекты
- •Создание деструкторов
- •Интерфейс iDisposable
- •Комбинирование подходов
- •Общие рекомендации по использованию Finalize и Dispose
- •Указатели
- •Ключевое слово unsafe
- •Операции * и &
- •Получение адреса
- •Операции с указателями
- •Указатель на другой указатель
- •Указатели на структуры, члены классов и массивы
- •Указатели на массивы и stackaloc
- •Оператор fixed и закрепление указателей
- •Dlr в c#. Ключевое слово dynamic
- •Сборки .Net
- •Роль сборок в приложениях .Net
- •Манифест сборки
- •Атрибуты сборки
- •Разделяемые сборки. Добавление сборки в gac
- •Строгое имя сборки
- •Многопоточность
- •Введение в многопоточность. Класс Thread
- •Получение информации о потоке
- •Статус потока
- •Приоритеты потоков
- •Создание потоков. Делегат ThreadStart
- •Потоки с параметрами и ParameterizedThreadStart
- •Синхронизация потоков
- •Мониторы
- •Класс AutoResetEvent
- •Мьютексы
- •Семафоры
- •Использование таймеров
- •Параллельное программирование и библиотека tpl
- •Задачи и класс Task
- •Массив задач
- •Работа с классом Task
- •Свойства класса Task
- •Возвращение результатов из задач
- •Задачи продолжения
- •Класс Parallel
- •Выход из цикла
- •Отмена задач и параллельных операций. CancellationToken
- •Отмена параллельных операций Parallel
- •Aсинхронное программирование
- •Асинхронные делегаты
- •IAsyncResult и методы BeginInvoke/EndInvoke
- •Асинхронные методы, async и await
- •Последовательный и параллельный вызов асинхронных методов
- •Обработка ошибок в асинхронных методах
- •Обработка исключений в async void-методах
- •Обработка нескольких исключений. WhenAll
- •Await в блоках catch и finally
- •Отмена асинхронных операций
- •Рефлексия
- •Введение в рефлексию. Класс System.Type
- •Получение типа
- •Применение рефлексии и исследование типов
- •Получение информации о методах
- •Получение конструкторов
- •Получение информации о полях и свойствах
- •Поиск реализованных интерфейсов
- •Динамическая загрузка сборок и позднее связывание
- •Позднее связывание
- •Атрибуты в .Net
- •Ограничение применения атрибута
- •Основы linq
- •Методы расширения linq
- •Список используемых методов расширения linq
- •Фильтрация выборки и проекция
- •Фильтрация
- •Выборка сложных объектов
- •Сложные фильтры
- •Проекция
- •Переменые в запросах и оператор let
- •Выборка из нескольких источников
- •Сортировка
- •Множественные критерии сортировки
- •Работа с множествами
- •Разность множеств
- •Пересечение множеств
- •Объединение множеств
- •Удаление дубликатов
- •Агрегатные операции
- •Метод Aggregate
- •Получение размера выборки. Метод Count
- •Получение суммы
- •Максимальное, минимальное и среднее значения
- •Методы Skip и Take
- •Группировка
- •Соединение коллекций. Метод Join, GroupJoin и Zip
- •Метод Zip
- •Методы All и Any
- •Отложенное и немедленное выполнение linq
- •Делегаты и анонимные методы в запросах linq
- •Работа с xml в c#
- •Работа с xml с помощью классов System.Xml
- •Изменение xml-документа
- •Удаление узлов
- •Linq to Xml. Создание Xml-документа
- •Выборка элементов в linq to xml
- •Изменение документа в linq to xml
- •Введение в Parallel linq. Метод AsParallel
- •Метод AsParallel
- •Метод ForAll
- •Метод AsOrdered
- •Обработка ошибок и отмена операции
- •Прерывание параллельной операции
- •Службы Windows
- •Создание службы для Windows
- •Установка службы
- •Сетевое программирование в с# и .Net
- •Основы работы с сетями в c# и .Net
- •Введение в сети и протоколы
- •Адреса в .Net
- •Отправка запросов
- •Класс WebClient
- •Классы WebRequest и WebResponse
- •Отправка данных в запросе
- •Обработка ошибок при запросах
- •Класс Socket
- •Общий принцип работы сокетов
- •Клиент-серверное приложение на сокетах tcp
- •Протокол tcp
- •Многопоточное клиент-серверное приложение tcp
- •Консольный tcp-чат
- •NetworkStream и текстовые потоки
- •Потоки бинарных данных
- •Протокол http
- •Руководство по Universal Windows Platform
- •Руководство по ado.Net и работе с базами данных
- •Глава 3. Работа с SqlDataAdapter и DataSet
- •Глава 4. Linq to sql
- •Введение в Entity Framework
- •Что такое Entity Framework
- •Способы взаимодействия с бд
- •Первое приложение с Entity Framework. Подход Code First
- •Взаимодействие с данными. Подходы
- •Code First к существующей базе данных
- •Соглашения по наименованию в Code First
- •Сопоставление типов
- •Названия таблиц и столбцов
- •Автоматизация Code First
- •Автоматизация Code First и ef Power Tools
- •Основы Entity Framework
- •Основные операции с данными
- •Добавление
- •Редактирование
- •Удаление
- •Строка подключения
- •Строка подключения в Model First и Database First
- •Навигационные свойства и lazy loading
- •Способы получения связанных данных
- •Связь один-к-одному
- •Связь один ко многим
- •Связь один ко многим. Практический пример
- •Связь многие ко многим
- •Инициализация базы данных
- •Параллелизм в Entity Framework
- •Управление транзакциями
- •Руководство по программированию для Xamarin Forms
- •Руководство по asp.Net Core
- •Паттерны проектирования в c# и .Net
- •Руководство по игростроению на платформе MonoGame
- •Задания для самостоятельного выполнения Рекомендации по выполнению практикума
- •Лабораторная работа. Алгебра логики и логические задачи.
- •Лабораторная работа. Алгоритмы. Алгоритмизация.
- •Цель и порядок работы
- •Контрольные вопросы
- •Задания
- •Лабораторная работа. Основы c# (.Net)
- •Работа с консолью и класс Console
- •Лабораторная работа. Основные операции с#. Выражения. Преобразование типов.
- •Лабораторная работа. Операторы языка c#
- •Лабораторная работа. Методы: основные понятия
- •Лабораторная работа. Рекурсивные методы
- •I. Разработать рекурсивный метод (возвращающий значение):
- •II. Разработка рекурсивных методов ( не возвращающих значений):
- •Лабораторная работа. Обработка исключений
- •Лабораторная работа. Массивы
- •I. Дана последовательность целых чисел.
- •II. Дана последовательность из n действительных чисел.
- •III. Дан массив размером n×n, элементы которого целые числа.
- •IV. Дан массив размером n×n, элементы которого целые числа.
- •Лабораторная работа. Символы и строки
- •Лабораторная работа. Регулярные выражения
- •Лабораторная работа. Организация с#-системы ввода-вывода
- •I. Работа с двоичными файлами:
- •II. Работа с текстовым (символьным) файлом.
- •Лабораторная работа. Работа с файловой системой
- •Лабораторная работа. Классы: основные понятия, данные, методы, конструкторы, свойства
- •Лабораторная работа. Классы: деструкторы, индексаторы, операции класса, операции преобразования типов
- •Лабораторная работа. Иерархия классов
- •Лабораторная работа. Интерфейсы и структуры
- •Лабораторная работа. Коллекции пространства имен System.Collection
- •Решить следующие задачи с использованием класса Stack:
- •Решить следующие задачи с использованием класса Queue:
- •Решить задачи из предыдущей лабораторной работы, используя класс ArrayList.
- •Лабораторная работа. Делегаты
- •Лабораторная работа. Сборки .Net
- •Лабораторная работа. Многопоточность
- •Лабораторная работа. Парелельное программирование и библиотека tpl.
- •Лабораторная работа. Сетевое программирование c#.
- •Лабораторная работа. Windows Universal Platform.
- •Лабораторная работа. Wup - проект.
- •Лабораторная работа. Ado.Net работа с базами данных
- •1. Библиотека
- •2. Университет
- •3. Оптовая база
- •4. Производство
- •5. Сеть магазинов
- •6. Авторемонтные мастерские
- •7. Деканат
- •8. Договорная деятельность организации
- •9. Поликлиника
- •10. Телефонная станция
- •11. Спорт
- •12. Сельскохозяйственные работы
- •13. Городской транспорт
- •14. География
- •15. Домоуправление
- •16. Аэропорт
- •Лабораторная работа. Entity Framework
- •1. Библиотека
- •2. Университет
- •3. Оптовая база
- •4. Производство
- •5. Сеть магазинов
- •6. Авторемонтные мастерские
- •7. Деканат
- •8. Договорная деятельность организации
- •9. Поликлиника
- •10. Телефонная станция
- •11. Спорт
- •12. Сельскохозяйственные работы
- •13. Городской транспорт
- •14. География
- •15. Домоуправление
- •16. Аэропорт
- •Лабораторная работа. Xamarin Forms
- •Лабораторная работа. Asp.Net mvc 5 / Core
Оператор fixed и закрепление указателей
Ранее мы посмотрели, как создавать указатели на типы значений, например, int или структуры. Однако кроме структур в C# есть еще и классы, которые в отличие от типов значений, помещают все связанные значения в куче. И в работу данных классов может в любой момент вмешаться сборщик мусора, периодически очищающий кучу. Чтобы фиксировать на все время работы указатели на объекты классов используется оператор fixed.
Допустим, у нас есть класс Person:
public class Person
{
public int age;
public int height;
}
Зафиксируем указатель с помощью оператора fixed:
unsafe
{
Person person = new Person();
person.age = 28;
person.height = 178;
// блок фиксации указателя
fixed(int* p = &person.age)
{
if (*p < 30)
{
*p = 30;
}
}
Console.WriteLine(person.age); // 30
}
Оператор fixed создает блок, в котором фиксируется указатель на поле объекта person. После завершения блока fixed закрепление с переменных снимается, и они могут быть подвержены сборке мусора.
Кроме адреса переменной можно также инициализировать указатель, используя массив, строку или буфер фиксированного размера:
unsafe
{
int[] nums = { 0, 1, 2, 3, 7, 88 };
string str = "Привет мир";
fixed(int* p = nums)
{
}
fixed(char* p = str)
{
}
}
При инициализации указателей на строку следует учитывать, что указатель должен иметь тип char*.
Dynamic Language Runtime
Dlr в c#. Ключевое слово dynamic
Хотя C# относится к статически типизированным языкам, в последних версиях языка были добавлены некоторые динамические возможности. Так, начиная с .NET 4.0 была добавлена новая функциональность под названием DLR (Dynamic Language Runtime). DLR представляет среду выполнения динамических языков, например, таких языков как IronPython и IronRuby.
Чтобы понять значение данного нововведение, нужно осознавать разичие между языками со статической и динамической типизицией. В языках со статической типизацией выявление всех типов и их членов - свойств и методов происходит на этапе компиляции. А в динамических языках системе ничего не известно о свойствах и методах типов вплоть до выполнения.
Благодаря этой среде DLR C# может создавать динамические объекты, члены которых выявляются на этапе выполнения программы, и использовать их вместе с традиционными объектами со статической типизацией.
Ключевым моментом использования DLR в C# является применение типов dynamic. Это ключевое слово позволяет опустить проверку типов во время компиляции. Кроме того, объекты, объявленные как dynamic, могут в течение работы программы менять свой тип. Например:
class Program
{
static void Main(string[] args)
{
dynamic x = 3; // здесь x - целочисленное int
Console.WriteLine(x);
x = "Привет мир"; // x - строка
Console.WriteLine(x);
x = new Person() { Name = "Tom", Age = 23 }; // x - объект Person
Console.WriteLine(x);
Console.ReadLine();
}
}
class Person
{
public string Name {get;set;}
public int Age { get; set; }
public override string ToString()
{
return Name + ", " + Age.ToString();
}
}
Несмотря на то, что переменная x меняет тип своего значения несколько раз, данный код будет нормально работать. В этом использование типов dynamic отличается от применения ключевого слова var. Для переменной, объявленной с помощью ключевого слова var, тип выводится во время компиляции и затем во время выполнения больше не меняется.
Также можно найти общее между использованием dynamic и типом object. Если в предыдущем примере мы заменим dynamic на object: object x = 3;, то результат будет тот же. Однако и тут есть различия. Например:
object obj = 24;
dynamic dyn = 24;
obj += 4; // так нельзя
dyn += 4; // а так можно
На строке obj += 4; мы увидим ошибку, так как операция += не может быть применена к типам object и int. С переменной, объявленной как dynamic, это пройдет, так как ее тип будет известен только во время выполнения.
Еще одна отличительная особенность использования dynamic состоит в том, что это ключевое слово применяется не только к переменным, но и к свойствам и методам. Например:
class Person
{
public string Name {get;set;}
public dynamic Age { get; set; }
// выводим зарплату в зависимости от переданного формата
public dynamic getSalary(dynamic value, string format)
{
if (format=="string")
{
return value + " рублей";
}
else if (format == "int")
{
return value;
}
else
{
return 0.0;
}
}
public override string ToString()
{
return Name + ", " + Age.ToString();
}
}
В классе Person определено динамическое свойство Age, поэтому при задании значения этому свойству мы можем написать иperson.Age=33, и person.Age="тридцать три". Оба варианта будут правильными.
Также есть метод getSalary, возвращающий значение dynamic. Например, в зависимости от параметра мы можем вернуть или строковое представление суммы дохода или численное. Также метод принимает dynamic в качестве параметра. Таким образом, мы можем передать в качестве значения дохода как целое, так и дробное число. Посмотрим на конкретное применение:
dynamic person1 = new Person() { Name = "Том", Age = 27 };
Console.WriteLine(person1);
Console.WriteLine(person1.getSalary(28.09, "int"));
dynamic person2 = new Person() { Name = "Билл", Age = "Двадцать два года" };
Console.WriteLine(person2);
Console.WriteLine(person2.getSalary(30, "string"));
DynamicObject и ExpandoObject
Интересные возможности при разработке в C# и .NET с использованием DLR предоставляет пространство именSystem.Dynamic и в частности класс ExpandoObject. Он позволяет создавать динамические объекты, наподобие тех, то используются в javascript:
dynamic viewbag = new System.Dynamic.ExpandoObject();
viewbag.Name = "Tom";
viewbag.Age = 46;
viewbag.Languages = new List<string> {"english", "german", "french" };
Console.WriteLine("{0} - {1}", viewbag.Name, viewbag.Age);
foreach (var lang in viewbag.Languages)
Console.WriteLine(lang);
// объявляем метод
viewbag.IncrementAge = (Action<int>)(x => viewbag.Age += x);
viewbag.IncrementAge(6); // увеличиваем возраст на 6 лет
Console.WriteLine("{0} - {1}", viewbag.Name, viewbag.Age);
Консольный вывод:
Tom - 46
english
german
french
Tom - 52
У динамического объекта ExpandoObject можно объявить любые свойства, например, Name, Age, Languages, которые могут представлять самые различные объекты. Кроме того, можно задать методы с помощью делегатов.
DynamicObject
На ExpandoObject по своему действию похож другой класс - DynamicObject. Он также позволяет задавать динамические объекты. Только в данном случае нам надо создать свой класс, унаследовав его от DynamicObject и реализовав его методы:
TryBinaryOperation(): выполняет бинарную операцию между двумя объектами. Эквивалентно стандартным бинарным операциям, например, сложению x + y)
TryConvert(): выполняет преобразование к определенному типу. Эквивалентно базовому преобразованию в C#, например, (SomeType) obj
TryCreateInstance(): создает экземпляр объекта
TryDeleteIndex(): удаляет индексатор
TryDeleteMember(): удаляет свойство или метод
TryGetIndex(): получает элемент по индексу через индексатор. В C# может быть эквивалентно следующему выражениюint x = collection[i]
TryGetMember(): получаем значение свойства. Эквивалентно обращению к свойству, например, string n = person.Name
TryInvoke(): вызов объекта в качестве делегата
TryInvokeMember(): вызов метода
TrySetIndex(): устанавливает элемент по индексу через индексатор. В C# может быть эквивалентно следующему выражению collection[i] = x;
TrySetMember(): устанавливает свойство. Эквивалентно присвоению свойству значения person.Name = "Tom"
TryUnaryOperation(): выполняет унарную операцию подобно унарным операциям в C#: x++
Каждый из этих методов имеет одну и ту же модель определения: все они возвращают логическое значение, показывающее, удачно ли прошла операция. В качестве первого параметра все они принимают объект связывателя или binder. Если метод представляет вызов индексатора или метода объекта, которые могут принимать параметры, то в качестве второго параметра используется массив object[] - он хранит переданные в метод или индексатор аргументы.
Почти все операции, кроме установки и удаления свойств и индексаторов, возвращают определенное значение (например, если мы получаем значение свойства). В этом случае применяется третий параметр out object vaue, который предназначен для хранения возвращаемого объекта.
Например, определение метода TryInvokeMember():
public virtual bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
Параметр InvokeMemberBinder binder является связывателем - получает свойства и методы объекта, object[] args хранит передаваемые аргументы, out object result предназначен для хранения выходного результата.
Рассмотрим на примере. Создадим класс динамического объекта:
class PersonObject : DynamicObject
{
Dictionary<string, object> members = new Dictionary<string, object>();
// установка свойства
public override bool TrySetMember(SetMemberBinder binder, object value)
{
members[binder.Name] = value;
return true;
}
// получение свойства
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
if (members.ContainsKey(binder.Name))
{
result = members[binder.Name];
return true;
}
return false;
}
// вызов метода
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = members[binder.Name];
result = method((int)args[0]);
return result != null;
}
}
Класс наследуется от DynamicObject, так как непосредственно создавать объекты DynamicObject мы не можем. И также здесь переопределяется три унаследованных метода.
Для хранения всех членов класса, как свойств, так и методов, определен словарь Dictionary<string, object> members. Ключами здесь являются названия свойств и методов, а значениями - значения этих свойств.
В методе TrySetMember() производится установка свойства:
bool TrySetMember(SetMemberBinder binder, object value)
Параметр binder хранит названием устанавливаемого свойства (binder.Name), а value - значение, которое ему надо установить.
Для получения значения свойства переопределен метод TryGetMember:
bool TryGetMember(GetMemberBinder binder, out object result)
Опять же binder содержит название свойства, а параметр result будет содержать значение получаемого свойства.
Для вызова методов определен метод TryInvokeMember:
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = members[binder.Name];
result = method((int)args[0]);
return result != null;
}
Сначала с помощью bindera получаем метод и затем передаем ему аргумент args[0], предварительно приведя его к типу int, и результат метода устанавливаем в параметре result. То есть в данном случае подразумевается, что метод будет принимать один параметр типа int и возвращать какой-то результат.
Теперь применим класс в программе:
static void Main(string[] args)
{
dynamic person = new PersonObject();
person.Name = "Tom";
person.Age = 23;
Func<int, int> Incr = delegate (int x) { person.Age+=x; return person.Age; };
person.IncrementAge = Incr;
Console.WriteLine("{0} - {1}", person.Name, person.Age); // Tom - 23
person.IncrementAge(4);
Console.WriteLine("{0} - {1}", person.Name, person.Age); // Tom - 27
Console.Read();
}
Выражение person.Name = "Tom" будет вызывать метод TrySetMember, в который в качестве второго параметра будет передаваться строка "Tom".
Выражение return person.Age; вызывает метод TryGetMember.
Также у объекта person определен метод IncrementAge, который представляет действия анонимного делегата delegate (int x) { person.Age+=x; return person.Age; }. Делегат принимает число x, увеличивает на это число свойство Age и возвращает новое значение person.Age. И при вызове этого метода будет происходить обращение к методу TryInvokeMember. И, таким образом, произойдет приращение значения свойства person.Age.
