Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Универсальные коллекции языка С#. Учебное пособие
.pdf
массива 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 это приветствие формируется
и выводится для всех элементов массива.
staticvoidMain(string[]args)
{
string[]name={"Иван","Степан","Федор","Олег","Николай"};
Action<string>greet=n=>
31

{
stringgreeting=$"Здравствуй,{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> Сохраняет пары «ключ-
значение»
SortedDictionary<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;
}
publicintproduct(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>, SortedList<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

publicstringCountry{get;set;}
publicintPopulation{get;set;}
publicoverridestringToString()
{
return$"{Country,15}\t{Population}";
}
publicoverrideboolEquals(objectobj)
{
if(obj==null)returnfalse;
CountriesobjAsCountries=objasCountries;
if(objAsCountries==
elsereturnEquals(objAsCountries);
}
publicoverrideintGetHashCode()
{
returnPopulation;
}
publicboolEquals(Countriesother)
{
if(other==null)returnfalse;
return(this.Country.Equals(other.Country));
}
publicintCompareTo(Countriesother)
{
return(this.Country.CompareTo(other.Country));
}
//Необходимоперегрузить==и!=операторы.
}
publicclassExample
{
//Методдлявыводасписканаконсоль.
staticvoidPrint<T>(inIEnumerable<T>coll,stringheader)
{
Console.WriteLine(header);
foreach(varelmincoll)
Console.WriteLine(elm);
Console.WriteLine();
}
publicstaticvoidMain()
{
//Созданиеспискаcountries(cтраны)
null)returnfalse;
38

//объектовCountries(Страны).
List<Countries>countries=newList<Countries>();
//ДобавляемобъектыCountries(Страны)ксписку.
countries.Add(newCountries()
{Country="Бельгия",Population= 11467923});
countries.Add(newCountries()
{Country="Франция",Population= 67028048});
countries.Add(newCountries()
{Country="Германия",Population= 83019214
countries.Add(newCountries()
{Country="Италия",Population= 60359546});
countries.Add(newCountries()
{Country="Люксембург",Population= 613894});
countries.Add(newCountries()
{Country="Ирландия",Population= 4904226});
countries.Add(newCountries()
{Country="Испания",Population= 46934632});
Console.WriteLine();
countries.Sort();//Сортировкасписка.
//Выводимсодержимоесписканамонитор.Будетвызыватьсяперегруженный
//ToStringметодклассаCountries.
Print(countries,"Отсортированныйсписоксountries:");
//Проверяемсписокнаналичие"Люксембург".
//Вызываетсяметод//IEquatable.Equalsметодкласса
//Countries,которыйпроверяетполе
//CountryклассаCountriesнаравенство.
Console.WriteLine("\nСодержит(\"Люксембург\"):{0}",
countries.Contains(newCountries
{Population=0,Country="Люксембург"}));
//Вставляетновыйэлементвпозицию2.
Console.WriteLine("\nInsert(2,\"Дания\")");
countries.Insert(2,newCountries()
{Country=
Print(countries,"Cписоксountriesпослевставкиэлемента\"Дания\":");
Console.WriteLine($"\nParts[3]:{countries[3]}");
//Будетудаленобъект"Италия"дажееслиполе
//Countryбудетиметь//другоезначение,
//потомучтоEqualsметодпроверяет
//толькополеCountryнаравенство.
countries.Remove(newCountries()
{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
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
