Учебное пособие (1077022), страница 16
Текст из файла (страница 16)
В качестве такого типа в .NETиспользуется тип KeyValuePair<TKey, TValue>. Объект такого типасодержит свойства Key и Value, возвращающие ключ и значение парысоответственно.У объекта класса словаря существуют коллекции ключей и значений:Keys и Values.133Пример вывода ключей и значений:Console.Write("\nКлючи: ");foreach (int i in d.Keys){Console.Write(i.ToString() + " ");}Console.Write("\nЗначения: ");foreach (string str in d.Values){Console.Write(str + " ");}Дляполучениязначенияпоключуможноиспользоватьперегруженный индексатор, что аналогично применению индексатора длясписка.Пример получения значения по ключу:int key = 3;string val = d[key];Console.WriteLine("\nДля ключа '" + key.ToString() +"' значение '" + val + "'");Однако если указать ключ, отсутствующий в словаре, то это приведетк возникновению исключения KeyNotFoundException.Для решения данной задачи можно также использовать методTryGetValue.
Он не генерирует исключение, а возвращает логическоезначение: true если удалось прочитать значение по ключу и false если неудалось.Пример использования метода TryGetValue:string val2 = "";bool res = d.TryGetValue(key, out val2);if (res){Console.WriteLine("\nДля ключа '" + key.ToString()+ "' значение '" + val2 + "'");}Обобщенные словари, как и обобщенные списки, часто используютсяв программах на C#.1346.1.5 КортежКортеж – это сравнительно новый вид коллекции, который появился вC# 4.0. Кортеж является не совсем классической коллекцией. Если,например, список можно представить в виде таблицы из одного столбца имножества строк, а словарь в виде таблицы из двух столбцов и множествастрок, то кортеж можно представить в виде таблицы из одной строки имножества столбцов.
Если список и словарь имеют фиксированнуюширину и могут расти только «по вертикали», то кортеж, наоборот, имеетфиксированную высоту и может расти только «по горизонтали».Столбцы определяются динамически с помощью обобщенных типов.Пример объявления кортежа:Tuple<int, string, string> group =new Tuple<int, string, string>(1, "ИУ", "ИУ-5");Если лямбда-выражения позволяют на лету объявлять методы, токортежи – структуры, подобные объектам классов.Когда программист хочет объявить какую-либо вспомогательнуюструктуру данных и не желает объявлять класс, он может воспользоватьсякортежем. Однако, недостаток кортежей состоит в том, что поля кортежа вIntelliSense представляются не в виде имен (как в классе) а в виде номеровполей (Item1 … ItemN).
Пример представлен на рис. 21.Рис. 21. Работа IntelliSense для кортежа.Кортеж не может содержать более восьми обобщенных типов, однакообобщенный тип может быть кортежем. Значит, если требуется135использовать более восьми полей, то можно создавать вложенныекортежи.Пример объявления вложенных кортежей:Tuple<int, int, int, int, int, int, int, Tuple<string, string, string>> tuple =new Tuple<int, int, int, int, int, int, int, Tuple<string, string, string>>(1, 2, 3, 4, 5, 6, 7, new Tuple<string, string, string>("str1", "str2", "str3"));Кортеж может выступать в качестве обобщенного типа для другихколлекций.Пример объявления списка, элементом которого является кортеж:List<Tuple<int, int, int>> tupleList =new List<Tuple<int, int, int>>();tupleList.Add(new Tuple<int, int, int>(1, 1, 1));tupleList.Add(new Tuple<int, int, int>(2, 2, 2));tupleList.Add(new Tuple<int, int, int>(3, 3, 3));Вместо кортежа в данном примере можно было создать отдельныйкласс, содержащий три целочисленных поля, и помещать в список объектыданного класса.6.1.6 Новый синтаксис кортежейВ предыдущем разделе мы рассмотрели классический для языка C#синтаксис кортежей.
В последнее время язык C# часто подвергалсякритике за то, что в нем не поддерживается упрощенный синтаксис дляработы с кортежами который используется в языке Python и многихязыках, поддерживающих функциональный подход, таких как Haskell и F#.В версии С# 7.0 этот подход был наконец реализован и мы рассматриваемего в данном разделе.Для работы с новым синтаксисом кортежей необходимо подключитьпакет «System.ValueTuple» с помощью диспетчера пакетов NuGet.Теперь кортеж может быть объявлен следующим образом сименованными параметрами:(string strParam, int intParam) tuple1 = ("строка", 333);Console.WriteLine(tuple1.strParam);Console.WriteLine(tuple1.intParam);136Результаты вывода в консоль:строка333Таким образом, тип-кортеж создается на лету и инициализируетсязначениями. В отличие от старого синтаксиса кортежей, где у полей былиимена Item1 … ItemN, в новом синтаксисе все поля имеют собственныеимена.Имена полей можно указывать в правой части, в этом случаекомпилятор автоматически выводит типы полей.
Следующий примераналогичен предыдущему:var tuple2 = (strParam: "строка", intParam: 333);Console.WriteLine(tuple2.strParam);Console.WriteLine(tuple2.intParam);Кортежявляетсяизменяемымтипомданных,полямможноприсваивать новые значения:tuple2.strParam = "новая строка";Кортежи можно использовать в качестве входных параметровфункций. Например, пусть объявлена следующая функция:public static void InputTuple((string strP, int intP) tupleParam) {}Ее можно вызвать следующим образом:InputTuple(tuple2);Обратите внимание, что имена параметров кортежей tuple2 иtupleParam не совпадают. Но ошибки не возникает, потому что совпадаютсигнатуры этих кортежей (у обоих два параметра, первый типа string, авторой типа int).Кортежи также можно использовать в качестве выходных параметровфункций. Например, пусть объявлена следующая функция, котораявозвращает кортеж:public static (string strParam, int intParam) OutputTuple(){return ("строка", 333);}137Ее можно вызвать следующим образом, в этом случае переменнаяtuple3 будет кортежем:var tuple3 = OutputTuple();Можно при вызове произвести разыменование кортежа, в этом случаепеременные str1 и int1 будут заполнены значениями из соответствующихполей кортежа:(string str1, int int1) = OutputTuple();Обратите внимание, что имена параметров кортежей (string strParam,int intParam) и (string str1, int int1) не совпадают.
Но ошибки не возникает,так как совпадают сигнатуры кортежей.Новый синтаксис кортежей упрощает создание типов, их передачу вфункции и возвращение из функций.6.1.7 Сортировка коллекцийДля большинства коллекций определен метод Sort, выполняющийсортировку коллекции. Если обобщенная коллекция основана на типезначении то это не вызывает проблемы, так как правила упорядочиванияэлементов для них известны.Пример сортировки коллекции для целых чисел:Console.WriteLine("\nСортировка списка целых чисел:");List<int> sl = new List<int>();sl.Add(5);sl.Add(3);sl.Add(2);sl.Add(1);sl.Add(4);Console.WriteLine("\nПеред сортировкой:");foreach (int i in sl) Console.Write(i.ToString() + " ");//Сортировкаsl.Sort();Console.WriteLine("\nПосле сортировки:");foreach (int i in sl) Console.Write(i.ToString() + " ");Результаты вывода в консоль:Сортировка списка целых чисел:Перед сортировкой:5 3 2 1 4138После сортировки:1 2 3 4 5Однако в случае использования объектов ссылочного типа в качествеэлементов коллекции возникает вопрос о том, как сортировать объектысложных классов.Рассмотрим дальнейшую работу с коллекциями на фрагментахпримера 11, который базируется на рассмотренных в примере 4 классахгеометрических фигур.Создание объектов классов фигур:Rectangle rect = new Rectangle(5, 4);Square square = new Square(5);Circle circle = new Circle(5);Добавление в список:List<Figure> fl = new List<Figure>();fl.Add(circle);fl.Add(rect);fl.Add(square);При вызове метода сортировки:fl.Sort();генерируется исключение InvalidOperationException с сообщением «сбойпри сравнении двух элементов массива».Возникновение этого исключения связано с тем, что в классегеометрической фигуры и ее наследниках нет информации о том, каксравнить элементы, что необходимо для сортировки элементов.Использование для коллекции метода Sort предполагает, что элементыколлекции реализуют интерфейс IComparable.
Наследование от данногоинтерфейсапредполагаетреализациюметодаCompareTo,осуществляющего сравнение двух объектов.Реализуем данный метод для класса «Геометрическая фигура»:public int CompareTo(object obj){//Приведение параметра к типу "фигура"Figure p = (Figure)obj;//Сравнение139if (this.Area() < p.Area()) return -1;else if (this.Area() == p.Area()) return 0;else return 1; //(this.Area() > p.Area())}В данном методе предполагается, что сравниваются два параметра,которые стоят слева и справа от оператора сравнения.Левый параметр – текущий объект класса (this), правый параметр –аргумент, передаваемый в метод (obj).Вначале obj приводится к типу «Геометрическая фигура». Затемпроизводится сравнение площади объекта this с площадью объекта obj.Если площадь this меньше, то метод возвращает -1, если площади равны то0, если площадь this больше, то 1.














