Главная страница
Навигация по странице:

  • Практическая работа № 1.18. Коллекции

  • Методические указания по выполнению лабораторных и практических работ по мдк


    Скачать 3.25 Mb.
    НазваниеМетодические указания по выполнению лабораторных и практических работ по мдк
    Дата23.01.2023
    Размер3.25 Mb.
    Формат файлаpdf
    Имя файла37._MU_PZ_PM.01_MDK_01.01_Razrabotka_programmnyx_moduley(1)_remo.pdf
    ТипМетодические указания
    #899980
    страница9 из 24
    1   ...   5   6   7   8   9   10   11   12   ...   24
    Практическая работа № 1.17. Работа с типом данных структура
    Цель работы: изучение типа данных структура
    Теоретический материал
    Типы структур
    Структуры по своей внутренней организации похожи на классы, они содержат набор полей и методов. Как правило, их используют для объявления типов, которые определяются только значениями полей и не имеют индивидуальности. Например, объекты, описывающие транзакции, несмотря на то, что значения их полей могут совпадать не будут тождественными, то есть нам их нужно уметь различать несмотря на внешнее сходство. А точки на геометрической плоскости, которые задаются двумя координатами, такой индивидуальности не имеют, и если координаты двух точек совпадают, то это значит, что речь идет об одной и той же точке. Именно для таких типов хорошо подходят структуры. Для их объявления используется ключевое слово struct: struct Point
    { public Point(double x, double y)
    {
    X = x;
    Y = y;
    } public double X {get;} public double Y {get;}
    }
    Point p1 = new Point(1,2);
    Console.WriteLine($”({p1.X}, (p1.Y})”);
    Типы значений, допускающие null
    Про типы значений, допускающих null см. ниже “Nullable-типы (нулевые типы) и операция ??”.
    Типы значений кортежей
    Кортежи используются для группировки данных, которые могут иметь разные типы в единую именованную сущность. Они являются объектами типа System.ValueTuple. Объявим кортеж, состоящий из двух элементов типа double:
    (double, double) tp1 = (1.0, 2.0); // явное задание типов элементов кортежа var tp2 = (8.1, 4.3); // использование var для объявления кортежа
    Поля кортежа могут быть именованными:
    (double X, double Y) tp3 = (3.2, 5.34); var tp4 = (X: 1.2, Y: 3.4); var X = 5.6; var Y = 7.8; var tp5 = (X, Y);
    Более подробно про кортежи типов System.ValueTuple (тип-значение) и System.Tuple
    (ссылочный тип) будет рассказано в одном из следующих уроков.
    Ссылочные типы
    Переменные ссылочного типа располагаются в куче, за их уничтожение отвечает сборщик мусора, поэтому про них нельзя точно сказать, когда занимаемая ими память будет освобождена.

    72
    Переменная представляется в виде ссылки на соответствующее место в куче. Ссылочные типы являются наследниками от System.Object.
    Типы классов
    Классы являются наиболее фундаментальным элементов в системе типов C#. Тип
    System.Object, который является родительским для всех типов данных представляет собой класс.
    Из рассмотренных выше типов данных, класс больше всего похож на структуру, у них даже объявление похожи, только вместо ключевого слова struct нужно использовать class. class Persone
    { public Persone(string name, int age)
    {
    Name = name;
    Age = age;
    } public string Name {get;set;} public int Age {get;set;}
    }
    Persone persone1 = new Persone("John", 21);
    Console.WriteLine($"Persone: Name: {persone1.Name}, Age: {persone1.Age})");
    Среди классов в C# можно выделить ряд классов, которые играю важную роль в языке, они перечислены в таблице ниже.
    Класс Описание
    System.Object Базовый класс для всех типов в C#
    System.ValueType
    Базовый класс для всех типов-значений
    System.Enum Базовый класс для всех перечислений
    System.Array Базовый класс для всех массивов
    System.Delegate
    Базовый класс для всех делегатов
    System.Exception
    Базовый класс для всех исключений
    System.String Класс, определяющий строкой тип данных
    Типы интерфейсов
    Интерфейс представляет собой набор методов, свойств, событий и индексаторов. До версии C# 8.0 интерфейс предполагал только декларацию (объявление) указанных выше элементов, начиная с 8.0, в рамках интерфейса можно располагать реализацию по умолчанию.
    Фактически интерфейс представляет собой контракт, а класс, который от него наследуюется, реализует этот контракт.
    Ход работы
    1. Создадим интерфейс для описания человека, у которого есть два свойства имя: Name, и возраст: Age: interface IPersone
    { string Name {get;set;} int Age {get;set;}
    }
    2. Изменим объявление класса Persone, так, чтобы он представлял реализацию интерфейса IPersone: class Persone: IPersone
    {
    //…
    }
    3. Объявим переменную типа IPersone:
    IPersone persone2 = new Persone("Jim", 25);
    Console.WriteLine($"Persone: Name: {persone2.Name}, Age: {persone2.Age})");
    Более подробно про интерфейсы будет рассказано в одном из следующих уроков.

    73
    Типы массивов
    Массив – это структура данных, которая позволяет хранить один или более элементов.
    Массивы в C# делятся на одномерные и многомерные, среди последних наибольшее распространение получили двумерные массивы. Все массивы являются наследниками класса
    System.Array.
    Создание и инициализация одномерного массива: int[] nArr1 = new int[5]; nArr1[0] = 0; nArr1[1] = 1; nArr1[2] = 2; nArr1[3] = 3; nArr1[4] = 4;
    Пример прямоугольного массива, в нем строки имеют одинаковую длину: int[,] nMx = new int[2,2]; // прямоугольный массив nMx[0,0]=0; nMx[0,1]=1; nMx[1,0]=2; nMx[1,1]=3;
    Пример зубчатого (jagged) массива, в нем строки могут иметь разную длину: int[][] jg = new int[2][]; // зубчатый массив jg[0] = new int[3]; jg[1] = new int[1];
    Более подробно про массивы будет рассказано в одном из следующих уроков.
    Типы делегатов
    Делегаты являются аналогом указателей на функции из языков C / C++. Они используются в случаях, когда нужно передать некоторую функциональность как аргумент, перенаправлять вызовы и т.д.
    Nullable-типы (нулевые типы) и операция ??
    Объявление и инициализация Nullable-переменных
    В работе с типами-значениями есть одна особенность, они не могут иметь значение null.
    При наличии любой из следующих строк кода, компиляция программы не будет выполнена: int nv = null; bool bv = null;
    На практике, особенно при работе с базами данных, может возникнуть ситуация, когда в записи из таблицы пропущены несколько столбцов (нет данных), в этом случае, соответствующей переменной нужно будет присвоить значение null, но она может иметь тип int или double, что приведет к ошибке.
    Можно объявить переменную с использованием символа ? после указания типа, тогда она станет nullable-переменной – переменной поддерживающей null-значение: int? nv1 = null; bool? bv1 = null;
    Использование символа ? является синтаксическим сахаром для конструкции
    Nullable, где T – это имя типа. Представленные выше примеры можно переписать так:
    Nullable nv1 = null;
    Nullable bv1 = null;
    Проверка на null. Работа с HasValue и Value
    Для того чтобы проверить, что переменная имеет значение null можно воспользоваться оператором is с шаблоном типа: bool? flagA = true; if(flagA is bool valueOfFlag)

    74
    {
    Console.WriteLine("flagA is not null, value: {valueOfFlag}");
    }
    Также можно воспользоваться свойствами класса Nullable:
    Nullable.HasValue
    Возвращает true если переменная имеет значение базового типа. То есть если она не null.
    Nullable.Value
    Возвращает значение переменной если HasValue равно true, иначе выбрасывает исключение InvalidOperationException. bool? flagB = false; if(flagB.HasValue)
    {
    Console.WriteLine("flagB is not null, value: {flagB.Value}");
    }
    Приведение Nullable-переменной к базовому типу
    При работе с Nullable-переменными их нельзя напрямую присваивать переменным базового типа. Следующий код не будет скомпилирован: double? nvd1 = 12.3; double nvd2 = nvd1; // error
    Для приведения Nullable-переменной к базовому типу можно воспользоваться явным приведением: double nvd3 = (double) nvd1;
    В этом случае следует помнить, что если значение Nullable-переменной равно null, то при выполнении данной операции будет выброшено исключение InvalidOperationException.
    Второй вариант – это использование оператора ??, при этом нужно дополнительно задаться значением, которое будет присвоено переменной базового типа если в исходной лежит значение null: double nvd4 = nvd1 ?? 0.0;
    Console.WriteLine(nvd4); bool? nvb1 = null; bool nvb2 = nvb1 ?? false;
    Console.WriteLine(nvb1);
    Console.WriteLine(nvb2);
    Второй вариант позволяет более лаконично обрабатывать ситуацию, когда вызов какого- то метода может возвращать null, а результат его работы нужно присвоить типу-значению, при этом заранее известно, какое значение нужно присвоить переменной в этой ситуации: static int? GetValue(bool flag)
    { if (flag == true) return 1000; else return null;
    } static void Main(string[] args)
    { int test1 = GetValue(true) ?? 123;
    Console.WriteLine(test1); int test2 = GetValue(false) ?? 123;
    Console.WriteLine(test2);
    }
    Ключевое слово dynamic

    75
    Вначале статьи мы говорили о том, что есть языки со статической и динамической типизацией, C# – язык со статической типизацией, т.е. типы переменных определяются на этапе компиляции. Но в рамках платформы .NET есть возможность работать с Python и Ruby в реализациях IronPython и IronRuby, но это языки с динамической типизацией, в них тип определяется во время выполнения программы. Для того чтобы можно было в C# проекте работать с тем, что было создано в рамках IronPython (или IronRuby) начиная с C# 4, в языке появилось ключевое слово dynamic и среда DLR (Dynamic Language Runtime), благодаря которой можно создавать динамические объекты, тип которых будет определен на этапе выполнения программы, а не в процессе компиляции.
    С помощью ключевого слова dynamic объявляются переменные, для которых нужно опустить проверку типов в процессе компиляции. Для этой переменной не производится присвоение типа из BCL (Base Class Library) – стандартной библиотеки классов .NET, фактически dynamic – это тип System.Object с дополнительным набором метаданных, они нужны для определения типа переменной в процессе выполнения (так называемое, позднее связывание).
    Ниже приведены несколько примеров, на которых можно разобраться с тем, как работать с dynamic:
    // Создадим переменную типа dynamic и проинициализируем ее double значением dynamic dval1 = 12.3;
    // Посмотрим на ее значение и тип
    Console.WriteLine($"Value: {dval1}");
    Console.WriteLine($"Type: {typeof(dval1)}"));
    // Изменим значение переменной: dval1 += 17;
    Console.WriteLine($"Value: {dval1}");
    Console.WriteLine($"Type: {typeof(dval1)}"));
    // Присвоим переменной значение другого типа: bool dval1 = true;
    // Посмотрим на ее значение и тип
    Console.WriteLine($"Value: {dval1}");
    Console.WriteLine($"Type: {typeof(dval1)}"));
    Как вы можете видеть значение и тип переменной dval1 менялись в процессе выполнения программы. При этом нужно помнить, что если вы присвоили переменной dynamic, какое-то значение, которое определило ее тип, а пытаетесь с ней работать как с переменной другого типа, то будет вызвано исключение: dynamic dval2 = "hello"; // в переменной dval2 хранится строковое значение
    Console.WriteLine($"Value: {dval2}");
    Console.WriteLine($"Type: {typeof(dval2)}"); dval2 = 123; // теперь значение типа int dval2 = dval2.ToUpper() // попытка вызвать на ней .ToUpper() приведет к ошибке
    Оператор default
    Оператор default создает значение по умолчанию для указанного типа, используется оно следующим образом: default(T), где T – это тип, для которого нужно создать соответствующее значение.
    4. Объявим переменную типа int и присвоим ей значение по умолчанию с помощью new: int n3 = new int();
    Console.WriteLine($"Default int value: {n3}");
    Тоже самое можно сделать с помощью оператора default: int n4 = default(int);
    Console.WriteLine($"Value of int that inited by default(T): {n4}");
    Если C# может самостоятельно вывести тип, то можно воспользоваться не оператором, а литерой default, без явного указания типа:

    76 int n5 = default;
    Console.WriteLine($"Value of int that inited by default: {n5}");
    Данный оператор полезен при разработке методов с обобщенным типом. Создадим метод, который выводит на консоль значение по умолчанию для типа переданного в нее аргумента: static void PrintDefaultValue(T val)
    {
    Console.WriteLine($"Type of val: {val.GetType()}, default value: {default(T)}, current value: {val}");
    }
    Вызовем эту функцию: static void Main(string[] args)
    {
    PrintDefaultValue(5);
    PrintDefaultValue(true);
    }
    Практическая работа № 1.18. Коллекции
    Цель работы: Изучение инструмента коллекций
    Теоретический материал
    Коллекции являются одним из наиболее часто используемых инструментов в разработке программного обеспечения. В этом уроке мы познакомимся с пространством имен
    System.Collections.Generic, коллекциями List, Dictionary и типом Tuple.
    Коллекции
    Самым примитивным способом хранения объектов в C# является использование массивов. Одной из основных проблем, с которой столкнется разработчик следуя такому подходу, является то, что массивы не предоставляют инструментов для динамического изменения размера. В языке C# есть два пространства имен для работы со структурами данных:
    System.Collections;
    System.Collections.Generic.
    Первое из них – System.Collections предоставляет структуры данных для хранения объектов типа Object. У этого решения есть две основных проблемы – это производительность и безопасность типов. В настоящее время не рекомендуется использовать объекты классов из
    System.Collections.
    Для решения указанных выше проблем Microsoft были разработаны коллекции с обобщенными типами (их ещё называют дженерики), они расположены в пространстве имен
    System.Collections.Generic. Суть их заключается в том, что вы не просто создает объект класса
    List, но и указываете, объекты какого типа будут в нем храниться, делается это так: List, где
    T может быть int, string, double или какой-то ваш собственный класс.
    В рамках данного урока мы не будем подробно останавливаться на особенностях обобщенных типов, на текущий момент можете их воспринимать как псевдонимы, для реальных типов данных.
    Коллекции в языке C#. Пространство имен System.Collections.Generic
    Пространство System.Collections.Generic содержит большой набор коллекций, которые позволяют удобно и эффективно решать широкий круг задач. Ниже, в таблице, перечислены некоторые из обобщенных классов с указанием интерфейсов, которые они реализуют.
    Обобщенный класс Основные интерфейсы
    Описание
    List
    ICollection, IEnumerable, IList
    Список элементов с динамически изменяемым размером
    Dictionary ICollection, IDictionary,
    IEnumerable
    Коллекция элементов связанных через уникальный ключ
    Queue
    ICollection, IEnumerable
    Очередь – список, работающий по алгоритму FIFO

    77
    Stack
    ICollection, IEnumerable
    Стэк – список, работающий по алгоритму
    LIFO
    SortedList IComparer,
    ICollection>,
    IDictionary Коллекция пар “ключ-значение”, упорядоченных по ключу
    Ход работы
    Класс List
    Коллекциями с класса List. Эта коллекция является аналогом типизированного массива, который может динамически расширяться. В качестве типа можно указать любой встроенный либо пользовательский тип.
    Задание 1. Создание объекта класса List
    Можно создать пустой список и добавить в него элементы позже, с помощью метода
    Add():
    List numsList = new List(); numsList.Add(1);
    Либо воспользоваться синтаксисом, позволяющем указать набор объектов, который будет храниться в списке:
    List nums = new List {1, 2, 3, 4, 5}; var words = new List {"one", "two", "three"};
    Работа с объектами List
    Ниже приведены таблицы, в которых перечислены некоторые полезные свойства и методы класса List. Более подробную информацию по методам и свойствам List вы можете найти в официальной документации.
    Свойства класса List
    Свойство
    Описание
    Count Количество элементов в списке
    Capacity
    Емкость списка – количество элементов, которое может вместить список без изменения размера
    Console.WriteLine("Свойства");
    Console.WriteLine($"- Count: nums.Count = {nums.Count}");
    Console.WriteLine($"- Capacity: nums.Capacity = {nums.Capacity}");
    Методы класса List
    Метод Описание
    Add(T)
    Добавляет элемент к списку
    BinarySearch(T)
    Выполняет поиск по списку
    Clear() Очистка списка
    Contains(T) Возвращает true, если список содержит указанный элемент
    IndexOf(T)
    Возвращает индекс переданного элемента
    ForEach(Action) Выполняет указанное действие для всех элементов списка
    Insert(Int32, T)
    Вставляет элемент в указанную позицию
    Find(Predicate) Осуществляет поиск первого элемент, для которого выполняется заданный предикат
    Remove(T)
    Удаляет указанный элемент из списка
    RemoveAt(Int32)
    Удаляет элемент из заданной позиции
    Sort() Сортирует список
    Reverse()
    Меняет порядок расположения элементов на противоположный
    Console.WriteLine($"nums: {ListToString(nums)}"); nums.Add(6);
    Console.WriteLine($"nums.Add(6): {ListToString(nums)}");
    Console.WriteLine($"words.BinarySearch(\"two\"): {words.BinarySearch("two")}");
    Console.WriteLine($"nums.Contains(10): {nums.Contains(10)}");
    Console.WriteLine($"words.IndexOf(\"three\"): {words.IndexOf("three")}");
    Console.WriteLine($"nums.ForEach(v => v * 10)"); nums.ForEach(v => Console.Write($"{v} => ")); nums.Insert(3, 7);

    78
    Console.WriteLine($"nums.Insert(3, 7): {ListToString(nums)}");
    Console.WriteLine($"words.Find(v => v.Length == 3): {words.Find(v => v.Length == 3)}"); words.Remove("two");
    Console.WriteLine($"words.Remove(\"two\"): {ListToString(words)}");
    Код метода ListToString: static private string ListToString(List list) =>
    "{" + string.Join(", ", list.ToArray()) + "}";
    Далее приведен пример работы со списком, в котором хранятся объекты пользовательского типа. Создадим класс Player, имеющий свойства: Name и Skill. class Player
    { public string Name { get; set; } public string Skill { get; set; }
    }
    Задание 2. Создадим список игроков и выполним с ним ряд действий:
    Console.WriteLine("Работа с пользовательским типом");
    List players = new List
    { new Player { Name = "Psy", Skill = "Monster"}, new Player { Name = "Kubik", Skill = "Soldier"}, new Player { Name = "Triver", Skill = "Middle"}, new Player { Name = "Terminator", Skill = "Very High"}
    };
    Console.WriteLine("Количество элементов в players:{0}", players.Count);
    //Добавим новый элемент списка players players.Insert(1, new Player { Name = "Butterfly", Skill = "flutter like a butterfly, pity like a bee"});
    //Посмотрим на все элементы списка players.ForEach(p => Console.WriteLine($"{p.Name}, skill: {p.Skill}"));
    Класс Dictionary
    Класс Dictionary реализует структуру данных Отображение, которую иногда называют
    Словарь или Ассоциативный массив. Идея довольно проста: в обычном массиве доступ к данным мы получаем через целочисленный индекс, в словаре используется ключ, который может быть числом, строкой или любым другим типом данных, который реализует метод GetHashCode(). При добавлении нового объекта в такую коллекцию для него указывается уникальный ключ, который используется для последующего доступа к нему.
    1   ...   5   6   7   8   9   10   11   12   ...   24


    написать администратору сайта