Книжная полка Сохранить
Размер шрифта:
А
А
А
|  Шрифт:
Arial
Times
|  Интервал:
Стандартный
Средний
Большой
|  Цвет сайта:
Ц
Ц
Ц
Ц
Ц

Современные технологии программирования. Язык С#.

В 2 томах. Том 2
Покупка
Основная коллекция
Артикул: 757947.01.01
Доступ онлайн
от 404 ₽
В корзину
Задача тома 2 учебника — подробно, доступно, на практических примерах изложить все возможности языка С#, одного из самых перспективных современных объектно-ориентированных языков программирования. Курс предполагает хорошее владение материалом, изложенным в томе 1 учебника, и предназначен для изучения дополнительных возможностей языка С#. Подробно рассмотрена работа со строками, датами и временем, с потоками и файловой системой, ISON и XML (на практических примерах) и др. В качестве среды разработки рассматривается среда Visual Studio.NET. Все примеры программ даны на языке C#. Соответствует требованиям федеральных государственных образовательных стандартов высшего образования последнего поколения. Предназначен студентам, обучающимся по направлению подготовки 09.03.03 «Прикладная информатика», студентам бакалавриата и магистратуры всех направлений подготовки и специальностей, а также аспирантам и слушателям ИПК.
Дадян, Э. Г. Современные технологии программирования. Язык С# : учебник : в 2 томах. Том 2. Для продвинутых пользователей / Э.Г. Дадян. — Москва : ИНФРА-М, 2021. — 335 с. — (Высшее образование: Бакалавриат). — DOI 10.12737/1478383. - ISBN 978-5-16-016997-2. - Текст : электронный. - URL: https://znanium.com/catalog/product/1478383 (дата обращения: 22.11.2024). – Режим доступа: по подписке.
Фрагмент текстового слоя документа размещен для индексирующих роботов
Москва
ИНФРА-М
2021

Э.Г. ДАДЯН

УЧЕБНИК

Рекомендовано Межрегиональным учебно-методическим 
советом профессионального образования в качестве учебника
для студентов высших учебных заведений, обучающихся
по направлению подготовки 09.03.03 «Прикладная информатика»
(квалификация (степень) «бакалавр»)
(протокол № 2 от 17.02.2021)

СОВРЕМЕННЫЕ 
ТЕХНОЛОГИИ 
ПРОГРАММИРОВАНИЯ

ЯЗЫК C#

В двух томах
Том 2. ДЛЯ ПРОДВИНУТЫХ ПОЛЬЗОВАТЕЛЕЙ

УДК 004.43(075.8)
ББК 32.973-018.1я73
 
Д14

Дадян Э.Г.

Д14  
Современные технологии программирования. Язык С# : учеб
ник :  в 2 т. Т. 2. Для продвинутых пользователей / Э.Г. Дадян. — 
Москва : ИНФРА-М, 2021. — 335 с. — (Высшее образование: Бакалавриат). — DOI 10.12737/1478383.

ISBN 978-5-16-016949-1 (общ.)
ISBN 978-5-16-016997-2 (т. 2, print)
ISBN 978-5-16-109578-2 (т. 2, online)
Задача тома 2 учебника — подробно, доступно, на практических при
мерах изложить все возможности языка С#, одного из самых перспективных современных объектно-ориентированных языков программирования. 
Курс предполагает хорошее владение материалом, изложенным в томе 1 
учебника, и предназначен для изучения дополнительных возможностей 
языка С#. Подробно рассмотрена работа со строками, датами и временем, 
с потоками и файловой системой, ISON и XML (на практических примерах) и др.

В качестве среды разработки рассматривается среда Visual Studio .NET. 

Все примеры программ даны на языке C#.

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

Предназначен студентам, обучающимся по направлению подготовки  

09.03.03 «Прикладная информатика», студентам бакалавриата и магистратуры всех направлений подготовки и специальностей, а также аспирантам 
и слушателям ИПК.

УДК 004.43(075.8)

ББК 32.973-018.1я73

Р е ц е н з е н т:

Барабаш Д.А., кандидат экономических наук, доцент, доцент Де
партамента анализа данных и машинного обучения Финансового 
университета при Правительстве Российской Федерации

ISBN 978-5-16-016949-1 (общ.)
ISBN 978-5-16-016997-2 (т. 2, print)
ISBN 978-5-16-109578-2 (т. 2, online)
© Дадян Э.Г., 2021

Данная книга доступна в цветном  исполнении 
в электронно-библиотечной системе Znanium.com

Предисловие

Том 2 учебника предназначен для продвинутых пользовате
лей, успешно освоивших материалы тома 1. Он состоит из 19 глав, 
дополнительных материалов для контроля знаний и библиографического списка. В томе 2 подробно, на конкретных практических 
примерах рассмотрены следующие дополнительные возможности 
объектно-ориентированного программирования на языке C#:
• практика объектно-ориентированного программирования;
• коллекции;
• дополнительные классы и структуры .net;
• многопоточность;
• параллельное программирование и библиотека tpl;
• aсинхронное программирование;
• linq;
• parallel linq;
• рефлексия;
• dynamic language runtime;
• сборка мусора, управление памятью и указатели;
• процессы и домены приложения;
• валидация модели. 

В конце учебника размещены:

• вопросы и задания для самостоятельной работы;
• примеры типовых заданий для самостоятельной работы;
• порядок решения типовых заданий;
• библиографический список.

Глава 1

ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ 

ОБЪЕКТНО-ОРИЕНТИРОВАННОГО 

ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ C#

1.1. МЕТОДЫ РАСШИРЕНИЯ

Методы расширения (extension methods) позволяют добавлять 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

class Program
{
    static void Main(string[] args)
    {
        string s = "Привет мир";
        char c = 'и';
        int i = s.CharCount(c);
        Console.WriteLine(i);

        Console.Read();
    }
}

public static class StringExtension
{
    public static int CharCount(this string str, char c)
    {
        int counter = 0;
        for (int i = 0; i<str.Length; i++)
        {
            if (str[i] == c)
                counter++;
        }
        return counter;
    }
} 

Чтобы создать метод расширения, сначала надо образовать ста
тический класс, содержащий указанный метод. В данном случае это 
класс StringExtension. Затем следует объявить статический метод. 
Суть нашего метода расширения — подсчет количества определенных символов в строке.

Метод расширения — это обычный статический метод, который 

в качестве первого параметра всегда принимает такую конструкцию: this имя типа название_параметра, т.е. в нашем случае this 
string str. Так как наш метод будет относиться к типу string, используем данный тип. Затем у всех строк можно вызвать данный 
метод: int i = s.CharCount(c);. Причем уже не надо указывать первый параметр. Значения остальных параметров передаются в обычном порядке.

Применение метода расширения очень удобно, но следует 

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

1.2. ЧАСТИЧНЫЕ КЛАССЫ И МЕТОДЫ

Классы могут быть частичными. То есть мы можем иметь не
сколько файлов с определением одного и того же класса, и при компиляции все эти определения будут объединены в один.

Например, определим в проекте два файла с кодом. Неважно, 

как эти файлы будут называться, например, PersonBase.cs и Person 
Additional.cs. В одном из этих файлов (не имеет значения, в каком 
именно) определим следующий класс:

1
2
3
4
5
6
7

public partial class Person
{
    public void Move()
    {
        Console.WriteLine("I am moving");
    }
}

В другом файле определим следующий класс:

1
2
3
4

public partial class Person
{
    public void Eat()
   {

5
6
7

        Console.WriteLine("I am eating");
    }
}

Таким образом, два файла в проекте содержат определение 

 одного и того же класса Person и включают два разных метода. 
Оба определенных здесь класса являются частичными. Для этого 
они формируются с ключевым словом partial (рис. 1.1).

Рис. 1.1

Затем можно использовать все методы класса Person:

1
2
3
4
5
6
7
8
9
10
11

class Program
{
    static void Main(string[] args)
    {
        Person tom = new Person();
        tom.Move();
        tom.Eat();

        Console.ReadKey();
    }
}

Частичные методы. Частичные классы могут содержать частич
ные методы, которые также определяются с ключевым словом 
partial. Причем определение частичного метода без его тела находится в одном частичном классе, а реализация этого метода — 
в другом. Например, изменим определенные выше классы Person. 

Первый класс:

1
2
3
4
5
6

public partial class Person
{
    partial void DoSomethingElse();

    public void DoSomething()
   {

7
8
9
10
11

        Console.WriteLine("Start");
        DoSomethingElse();
        Console.WriteLine("Finish");
    }
}

Второй класс:

1
2
3
4
5
6
7

public partial class Person
{
    partial void DoSomethingElse()
    {
        Console.WriteLine("I am reading a book");
    }
}

В первом классе определен метод DoSomethingElse, который 

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

При этом частичные методы не могут иметь модификаторов до
ступа — по умолчанию они все считаются приватными. Также частичные методы не могут иметь такие модификаторы, как virtual, 
abstract, override, new, sealed. Хотя допустимы статические частичные методы.

Кроме того, частичные методы не могут возвращать значения, 

т.е. они всегда имеют тип void, также они не могут иметь out-параметров.

Поскольку частичные методы всегда приватные, нельзя иx вы
звать напрямую в программе вне классов, где они определены. 
 Поэтому обычно они вызываются с помощью других доступных 
методов, как в случае выше посредством метода DoSomething:

1
2

Person tom = new Person();
tom.DoSomething();

1.3. АНОНИМНЫЕ ТИПЫ

Анонимные типы позволяют создавать объекты с некоторым на
бором свойств без определения класса и определяются с помощью 
ключевого слова var и инициализатора объектов:

1
2

var user = new { Name = "Tom", Age = 34 };
Console.WriteLine(user.Name);

В данном случае user — это объект анонимного типа, у которого 

определены два свойства — Name и Age. Также можно использовать его свойства, как у обычных объектов классов. Однако есть 
ограничение — свойства анонимных типов доступны только для 
чтения.

При этом во время компиляции компилятор сам будет соз
давать для него имя типа и использовать его при обращении к объекту. Нередко анонимные типы имеют имя наподобие "<>f__
AnonymousType0'2".

Для исполняющей среды CLR анонимные типы будут так же, 

как и классы, представлять ссылочный тип.

Если в программе используются несколько объектов анонимных 

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

1
2
3
4
5
6

7

var user = new { Name = "Tom", Age = 34 };
var student = new { Name = "Alice", Age = 21 };
var manager = new { Name = "Bob", Age = 26, Company = "Microsoft" };

Console.WriteLine(user.GetType().Name); // <>f__AnonymousType0'2
Console.WriteLine(student.GetType().Name); // <>f__
AnonymousType0'2
Console.WriteLine(manager.GetType().Name); // <>f__
AnonymousType1'3

Здесь user и student имеют одно и то же определение аноним
ного типа. Однако подобные объекты нельзя преобразовать к какому-нибудь другому типу, например классу, даже если он имеет 
подобный набор свойств. Следует учитывать, что свойства анонимного объекта доступны для установки только в инициализаторе. 
Вне инициализатора присвоить им значение невозможно. Поэтому, 
например, в следующем случае мы столкнемся с ошибкой:

1
2

var student = new { Name = "Alice", Age = 21 };
student.Age = 32;  // ! Ошибка

Кроме использованной выше формы инициализации, когда 

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

1
2
3

class User
{
    public string Name { get; set; }

4
5
6
7
8
9
10
11
12
13
14
15
16

}
class Program
{
    static void Main(string[] args)
    {
        User tom = new User { Name = "Tom" };
        int age = 34;
        var student = new { tom.Name, age}; // инициализатор с проекцией
        Console.WriteLine(student.Name);
        Console.WriteLine(student.age);
        Console.Read();
    }
}

В данном случае определение анонимного объекта фактически 

будет идентично следующему:

1
var student = new { Name = tom.Name, age = age};

Названия свойств и переменных (Name и age) используются 

в качесте названий свойств объекта. Также можно определять массивы объектов анонимных типов:

1
2
3
4
5
6
7
8
9

var people = new[]
{
    new {Name="Tom"},
    new {Name="Bob"}
};
foreach(var p in people)
{
    Console.WriteLine(p.Name);
}

Зачем нужны анонимные типы? Иногда возникает необхо
димость использования одного типа в одном узком контексте или 
даже один раз. Создание класса для подобного типа может быть 
избыточным. Если хочется добавить свойство, то сразу же на месте 
анонимного объекта это можно сделать. В случае с классом придется изменять еще и класс, который может больше нигде не использоваться. Типичная ситуация — получение результата выборки из базы данных: объекты используются только для получения выборки, часто больше нигде не используются, и классы для 
них создавать излишне. А вот анонимный объект прекрасно подходит для временного хранения выборки.

1.4. ЛОКАЛЬНЫЕ ФУНКЦИИ

Локальные функции — функции, определенные внутри других 

методов. Определим и используем локальную функцию:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

class Program
{
    static void Main(string[] args)
    {
        var result = GetResult(new int[] { -3, -2, -1, 0, 1, 2, 3 });
        Console.WriteLine(result); // 6
        Console.Read();
    }

    static int GetResult(int[] numbers)
    {
        int limit = 0;
        // локальная функция
        bool IsMoreThan(int number)
        {
            return number > limit;
        }

        int result = 0;
        for(int i=0; i < numbers.Length; i++)
        {
            if (IsMoreThan(numbers[i]))
            {
                result += numbers[i];
            }
        }

        return result;
    }
}

Здесь методом GetResult определена локальная функция 

IsMoreThan(), которая может быть вызвана только внутри этого 
метода. Локальная функция задает еще одну область видимости, 
где можно определять переменные и выполнять над ними действия. 
В то же время ей доступны все переменные, которые определены 
в том же методе.

При использовании локальных функций следует помнить, 

что они не могут иметь модификаторов доступа (public, private, 
protected). Нельзя определить в одном методе несколько локальных 

Доступ онлайн
от 404 ₽
В корзину