Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Универсальные коллекции языка С#. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
массива int[] v на k. Лямбда-выражение может захватывать перемен­ные окружения, в данном примере – это переменная k.
staticvoidMain(string[]args) { Func<int,int>d2=x=>x*x; int[]v={1,2,3,4,5,6,7}; doublet=0; t=v.Average(d2); Console.WriteLine($"Среднеесуммыквадратовэлементов={t}");  intk=2; t=v.Average(x=>x*k); Console.WriteLine($"Среднеепроизведенийэлементовнаk={t}"); } Результатработыпримера: Среднеесуммыквадратовэлементов=20 Среднеепроизведенийэлементовнаk=8
ЛЯМБДА-ОПЕРАТОРЫ
Второй разновидностью лямбда-выражения является лямбда­оператор. Для лямбда-оператора характерны расширенные возможно­сти выполнения различных операций, поскольку в его теле допускает­ся указывать несколько операторов. Например, в лямбда-операторе можно использовать циклы и условные операторы if, объявлять пере­менные и т. д. Чтобы создать лямбда-оператор, необходимо заключить тело выражения в
фигурные скобки. Кроме возможности использовать несколько операторов, лямбда-оператор практически ничем не отлича­ется от лямбда-выражения.
В приведенном ниже примере демонстрируется применение лямбда­оператора, который из принимаемого параметра типа string и элемента массива строк name формирует и выводит на консоль строку привет­ствия. С помощью метода ForEach класса Array это приветствие фор­мируется
и выводится для всех элементов массива.
staticvoidMain(string[]args) { string[]name={"Иван","Степан","Федор","Олег","Николай"}; Action<string>greet=n=>
31
{ stringgreeting=$"Здравствуй,{n}!"; Console.WriteLine(greeting); }; Array.ForEach(name,greet); }  Результатработыпримера: Здравствуй,Иван! Здравствуй,Степан! Здравствуй,Федор! Здравствуй,Олег! Здравствуй,Николай!
КОНТРОЛЬНЫЕ ВОПРОСЫ
1. Что такое делегат и для чего он предназначен?
2. Что такое анонимная функция и для чего ее используют?
3. Что такое лямбда выражение и для чего оно предназначено?
4. Что такое лямбда оператор и для чего он предназначен?
5. Для чего предназначен класс Func?
6. Для чего предназначен класс
Action?
7. Для чего предназначен класс Predicate?
КЛАССЫ ОБОБЩЕННЫХ (УНИВЕРСАЛЬНЫХ)
КОЛЛЕКЦИЙ
Kлассы обобщенных коллекций обеспечивают возможность хра­нения и обработки данных произвольных, заданных пользователем ти­пов. По большей части они соответствуют своим необобщенным ана­логам, хотя в некоторых случаях и носят другие имена. Обобщенные коллекции различаются своей организацией и функциональными воз­можностями. Классы обобщенных коллекций определяются в про­странстве имен System.Collections.Generic и класса Object. В таблице ниже перечислены основные классы обоб­щенных коллекций и приведены их аналоги в С++.
32
являются наследниками
Кооллекция Назначение
у
Stack<T> Создает стек Стек (stack) Queue<T> Создает очередь Очередь (queue) LinkedList<T> Сохраняет элементы
в двунаправленном списке
SortedList<TKeyTValue> Создает отсортированный
список из пар «ключ-зна­чение»
List<T> Создает динамический мас-
сив
HashSet<T> Сохраняет ряд уникальных
значений, используя хеш­таблиц
SortedSet<T> Создает отсортированное
множество
Dictionary<TKeyTValue> Сохраняет пары «ключ-
значение»
SortedDiction­ary<TKeyTValue>
Создает отсортированный список из пар «ключ­значение»
Аналогичный
контейнер С++
Список (list)
Нет аналога
Вектор (vector)
Множество (set)
Словарь (dictionary)
НАСТРОЙКА КОЛЛЕКЦИЙ
Коллекции С# – универсальное средство решения задач обработки данных. Они позволяют хранить и обрабатывать данные как стандарт­ных (определенных в языке) типов, так и пользовательских типов. По­этому в них предусмотрен набор инструментов настройки коллекции на особенности задач пользователя.
Для того чтобы приспособить поведение коллекции к требованиям, предъявляемым задачей,
которую вы решаете, имеются инструменты
настройки коллекций, к которым можно отнести:
параметры конструкторов, с помощью которых вы можете: со- здать новую коллекцию, инициировав ее элементами существующей; задать компаратор (функция сравнения), определяющий необходимые вам правила сравнения объектов, помещаемых в коллекцию;
параметры методов, представленные делегатами, которые позво- ляют изменять поведение методов
.
33
Как правило, настраивать объекты стандартных типов для их обра­ботки с помощью коллекций нет необходимости. Однако если вы хо­тите с помощью коллекций обрабатывать объекты пользовательского типа (классы, структуры), вам необходимо их настроить для работы с выбранной коллекцией, для этой цели следует реализовать в классе ваших объектов интерфейсы, требуемые для выбранной
коллекции,
и переопределить или определить некоторые методы.
НАСТРОЙКА МЕТОДОВ РАСШИРЕНИЯ КОЛЛЕКЦИЙ
Классы универсальных коллекций содержат достаточно большое число методов для обработки элементов коллекций. Однако учесть все возможные проблемы, с которыми столкнутся потенциальные пользо­ватели, невозможно. Поэтому разработчики коллекций создают уни­версальные методы, поведение которых можно изменять, передавая в них необходимые
пользователю функции, которые будут обрабаты­вать элементы коллекции в составе метода. Передача функций в метод основана на использовании в качестве параметра метода ссылочного типа delegate (см. Делегаты), объекты которого могут ссылаться на ме­тоды с определенной в делегате сигнатурой. Настройка метода расши­рения на особенности вашей задачи состоит в том, что при
вызове ме­тода коллекции с параметром типа делегат вы можете передать в него в качестве параметра метод класса, написанного вами. Помимо методов класса можно передавать и лямбда-выражения (см. раздел Лямбды).
В качестве примера рассмотрим коллекцию List<int>. Эта коллек­ция предоставляет метод расширения Sum, с помощью которого вы можете вычислить сумму последовательности
значений, как показано
в примере ниже:
List<int>lst=newList<int>(){2,5,1,4,7,3,9}; intresult=lst.Sum(); Console.WriteLine($"Суммаэлементовlst={result}");
Результа работы примера:
Суммаэлементовlst=31
Однако пользователю может потребоваться складывать не сами значения, хранящиеся в коллекции, а результаты их фукционального преобразования. Для этой цели имеется перегруженный метод расши-
34
рения Sum, с помощью которого можно вычислить сумму последова­тельности значений типа int, получаемую в результате применения функции преобразования к каждому элементу входной последователь­ности. Вместо параметра-делегата в метод Sum можно передать лямб­да-выражение, реализующее функцию с требуемой сигнатурой, как показано в примере ниже:
List<int>lst=newList<int>(){2,5,1,4,7,3,9}; //Функциявозведениявквадратдляпреобразованияэлементов //передсложениемзаданалямбда‐выражением. result=lst.Sum(x=>x*x); Console.WriteLine($"Суммаквадратовэлементовlst={result}");
Результат работы примера:
Суммаквадратовэлементовlst=185
Если у вас есть класс с методами, подходящими для функциональ­ного преобразования значений элементов коллекции, вы можете пере­дать в метод Sum методы класса, используя делегат, как показано в примере ниже:
classMyClass { publicstaticintsq(intx) { returnx*x; } publicintproduct(intx) { returnx*2; } }  classProgram { staticvoidMain(string[]args) {  List<int>lst=newList<int>(){2,5,1, //ПередаемссылкунастатическийметодproductклассаMyClassделегатуDl. Func<int,int>Dl=MyClass.sq; intresult=lst.Sum(Dl);
4,7,3,9};
35
Console.WriteLine($"Суммаквадратовэлементовlst={result}");  //СоздаемобъектклассаMyClass. MyClassobj=newMyClass(); //ПередаемссылкунаметодproductклассаMyClassделегатуDl1. Func<int,int>Dl1=obj.product; result=lst.Sum(Dl1); Console.WriteLine($"Суммапроизведенияэлементовlstна3={result}"); } }
Результат работы примера:
Суммаквадратовэлементовlst=185 Суммапроизведенияэлементовlstна3=62
УНИВЕРСАЛЬНЫЕ СПИСКИ-КОЛЛЕКЦИЯ LIST<T>,
SORTEDLIST<>, LINKEDLIST<>
В составе С# имеются три универсальных списка: List<T>, Sorted­List<T> и LinkedList<T>. Эти коллекции имеют сходную функцио-
нальность, но отличаются способом организации элементов списка, а значит, и временной сложностью выполнения операций вставки, уда­ления, поиска элементов и прохождения по элементам списка.
КОЛЛЕКЦИЯ LIST<T>-СПИСОК
Объекты этого класса представляют строго типизированный спи­сок объектов типа Т, доступных по индексу. Класс поддерживает ме­тоды для поиска по списку, выполнения сортировки и других операций со списками. Класс List<T> реализует следующие интерфейсы (см. раздел Интерфейсы):
ICollection<T>,IEnumerable<T>,IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection,IEnumerable,IList
Класс List<T> является универсальным эквивалентом ArrayList класса. Он реализует универсальный интерфейс IList<T> с помощью массива, размер которого динамически увеличивается по мере необхо­димости.
36
Элементы можно добавлять в List<T> с помощью методов Add или AddRange.
Класс List<T> использует и компаратор равенства, и компаратор упорядочения.
Методы Contains, IndexOf, LastIndexOf, Remove используют
компаратор проверки на равенство для элементов списка. Компаратор проверки на равенство по умолчанию для типа T определяется следу­ющим образом. Если тип T реализует IEquatable<T> универсальный интерфейс, компаратором проверки на равенство является метод Equals(T) этого интерфейса; в противном случае компаратором по умолчанию будет метод Object.Equals(Object).
Методы BinarySearch и Sort используют компаратор упорядоче-
ния для элементов списка. Компаратор по умолчанию для типа T опре­деляется следующим образом. Если тип T реализует IComparable<T> универсальный интерфейс, то компаратором по умолчанию является метод CompareTo(T) этого интерфейса; в противном случае, если тип T реализует неуниверсальный IComparable интерфейс, компаратором по умолчанию является метод CompareTo(Object) этого интерфейса. Если тип T не реализует ни того ни другого, то компаратор по умолчанию отсутствует, а компаратор или делегат (см. раздел Делегаты) сравнения необходимо предоставить явным образом.
Перед выполнением операций (например, BinarySearch), для кото­рых требуется сортированный список, необходимо отсортировать
List<T>.
Доступ к элементам в этой коллекции можно получить с помощью целочисленного индекса. Индексы в ней отсчитываются от нуля. Ниже приведены примеры работы с коллекцией List<T>.
В следующем примере показано, как добавить, удалить и вставить простой
usingSystem; usingSystem.Collections.Generic;
namespaceПример_1 { //КлассCountries(Страны).ПолеCountryидентифицируетобъект, //полеPopulationчисленностьнаселениявтысячахчеловек.
publicclassCountries:IEquatable<Countries>,IComparable<Countries> {
бизнес-объект класса Countries в список List<T>.
37
publicstringCountry{get;set;} publicintPopulation{get;set;} publicoverridestringToString() { return$"{Country,15}\t{Population}"; } publicoverrideboolEquals(objectobj) { if(obj==null)returnfalse; CountriesobjAsCountries=objasCountries; if(objAsCountries== elsereturnEquals(objAsCountries); } publicoverrideintGetHashCode() { returnPopulation; } publicboolEquals(Countriesother) { if(other==null)returnfalse; return(this.Country.Equals(other.Country)); } publicintCompareTo(Countriesother) { return(this.Country.CompareTo(other.Country)); } //Необходимоперегрузить==и!=операторы. }  publicclassExample { //Методдлявыводасписканаконсоль. staticvoidPrint<T>(inIEnumerable<T>coll,stringheader) { Console.WriteLine(header); foreach(varelmincoll) Console.WriteLine(elm); Console.WriteLine(); }  publicstaticvoidMain() { //Созданиеспискаcountries(cтраны)
null)returnfalse;
38
//объектовCountries(Страны). List<Countries>countries=newList<Countries>(); //ДобавляемобъектыCountries(Страны)ксписку. countries.Add(newCountries() {Country="Бельгия",Population= 11467923}); countries.Add(newCountries() {Country="Франция",Population= 67028048}); countries.Add(newCountries() {Country="Германия",Population= 83019214 countries.Add(newCountries() {Country="Италия",Population= 60359546}); countries.Add(newCountries() {Country="Люксембург",Population= 613894}); countries.Add(newCountries() {Country="Ирландия",Population= 4904226}); countries.Add(newCountries() {Country="Испания",Population= 46934632}); Console.WriteLine(); countries.Sort();//Сортировкасписка.
//Выводимсодержимоесписканамонитор.Будетвызыватьсяперегруженный //ToStringметодклассаCountries.
Print(countries,"Отсортированныйсписоксountries:"); //Проверяемсписокнаналичие"Люксембург". //Вызываетсяметод//IEquatable.Equalsметодкласса //Countries,которыйпроверяетполе //CountryклассаCountriesнаравенство. Console.WriteLine("\nСодержит(\"Люксембург\"):{0}", countries.Contains(newCountries {Population=0,Country="Люксембург"})); //Вставляетновыйэлементвпозицию2. Console.WriteLine("\nInsert(2,\"Дания\")"); countries.Insert(2,newCountries() {Country= Print(countries,"Cписоксountriesпослевставкиэлемента\"Дания\":"); Console.WriteLine($"\nParts[3]:{countries[3]}"); //Будетудаленобъект"Италия"дажееслиполе //Countryбудетиметь//другоезначение, //потомучтоEqualsметодпроверяет //толькополеCountryнаравенство. countries.Remove(newCountries() {Population=0,Country="Италия"}); Print(countries,"Cписокcountriesпослеудаленияэлемента\"Италия\":"); //Удаляемзаписьподиндексом3.
"Дания",Population=5806081});
});
39
countries.RemoveAt(3); Print(countries,"Cписокcountriesпослеудаленияэлементаподиндексом3:"); } } }  Результатработыпрограммы: Отсортированныйсписоксountries: Бельгия11467923 Германия83019214 Ирландия4904226 Испания46934632 Италия60359546 Люксембург613894 Франция67028048  Содержит("Люксембург"):True 
Insert(2,"Дания") Cписоксountriesпослевставкиэлемента"Дания":
Бельгия11467923 Германия83019214 Дания5806081 Ирландия4904226 Испания46934632 Италия60359546 Люксембург613894 Франция67028048 
Parts[3]:Ирландия4904226 Cписокcountries
Бельгия11467923 Германия83019214 Дания5806081 Ирландия4904226 Испания46934632 Люксембург613894 Франция67028048  Cписокcountriesпослеудаленияэлементаподиндексом3: Бельгия11467923 Германия83019214 Дания5806081
послеудаленияэлемента"Италия":
40
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]